home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / STACY / AHDI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  98.3 KB  |  3,285 lines

  1. ; Apr 24 1990 v3.02
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST                :
  6. ;    Copyright 1985,1986,1987,1988,1989 Atari Corp.            :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;----------------
  13. ;
  14. ;  Conditional Assembly Switches
  15. ;
  16. format        equ    0        ; Format code
  17. mdsense        equ    0        ; Mode Sense code
  18. ospool        equ    1        ; increase size of OS pool for ROM
  19. onscreen    equ    0        ; show that ACSI 0 is parked
  20.  
  21.  
  22. ;
  23. ;-------------------- Edit History ------------------------
  24.  
  25. ;------------------
  26. ;                                    :
  27. ;  9-Apr-1985 lmd    Hacked it up.  "Gee, it seems to work ..."    :
  28. ; 14-Apr-1985 lmd    linked with BIOS (***FOR NOW***)        :
  29. ; 20-Apr-1985 lmd    hacked for WD controller (now, wired...)    :
  30. ; 24-Jun-1985 jwt    hacked for Adaptec, new kludge board        :
  31. ; 01-Jul-1985 jwt    seems to work, add more formatting and more    :
  32. ;             detailed error reporting            :
  33. ; 22-Jul-1985 jwt    change timing of wdc/wdl at start of command,    :
  34. ;             added extra move.w $8a,wdl to change A1    :
  35. ; 23-Jul-1985 jwt    use a move.l instruction for all wdc/wdl write    :
  36. ;             pairs since it changes A1 quickly enough that    :
  37. ;             the (old) DMA chip does not incorrectly    :
  38. ;             generate two chip selects            :
  39. ; 26-Sep-1985 jwt v0.05    support multiple ACSI devices            :
  40. ;            separate timeouts for command packet and    :
  41. ;             operation                    :
  42. ; 01-Oct-1985 jwt v0.06    added some AUXout serial debug messages        :
  43. ;            was responding to one more drive than was there    :
  44. ; 07-Oct-1985 jwt v0.07    added support for multiple partitions/drive    :
  45. ; 11-Oct-1985 jwt v0.08 added delay loop after pread for completion    :
  46. ;             byte                        :
  47. ; 19-Oct-1985 jwt v0.09    remove format and simple commands from resident :
  48. ;             part                        :
  49. ;            conditional assembly for default size        :
  50. ;            added count parameter to pread            :
  51. ; 22-Oct-1985 jwt v0.10    make certain qdone returns d0=-1 on timeout    :
  52. ;            add bits to read/write flag for:        :
  53. ;             retry disable (bit 2)                :
  54. ;             physical unit operation (bit 3)        :
  55. ;            add pun_ptr to TOS global variables        :
  56. ; 24-Oct-1985 jwt v0.11    add critical error call on errors        :
  57. ; 30-Jan-1986 lmd v0.12    increase OS pool by 128 chunks for ROM release    :
  58. ;             of 11/20/85                    :
  59. ;          jwt    stay resident if any physical units found    :
  60. ;             rather than if any GEM partitions found    :
  61. ; 05-Feb-1986 jwt    call critical error handler on errors unless    :
  62. ;             no-retry bit is set                :
  63. ;            conditional assembly format code        :
  64. ;            remove transfer only to even byte boundary    :
  65. ;             restriction                    :
  66. ;            remove transfer less than 128K restriction    :
  67. ;            check for 0 length transfer            :
  68. ; 06-Feb-1986 jwt v0.13    use register based accesses for wdc and wdl    :
  69. ; 25-Mar-1986 lmd v0.14 Enforce .005 (200th) sec delay between        :
  70. ;             successive calls to _do_rw().  SCSI adapter    :
  71. ;             board eats the controller's completion byte,    :
  72. ;             so we have to delay for it.            :
  73. ; 24-Apr-1986 lmd v1.1    Hack pool_install code to increase pool for    :
  74. ;             other ROM releases of the system.        :
  75. ; 24-Apr-1986 lmd v1.4    Print nasty messages for old disk-based and    :
  76. ;             unauthorized ROM-based systems.        :
  77. ; 23-Jun-1987 lmd v1.5  Fix date-check in nasty-OS-message code; wrong    :
  78. ;             offset into the OS header (now $1e).        :
  79. ; 06-Nov-1987 akp v1.7    Added procedure findpackages and call to it.    :
  80. ; 10-Nov-1987 akp    Changed source to MADMAC format.        :
  81. ;            Removed format flag from top of file.        :
  82. ; 24-Nov-1987 akp    Really made v1.7 work.                :
  83. ; 19-Feb-1988 ml    Added format and mode sense code for use in     :
  84. ;             HDX  (It's conditional, code will only be    :
  85. ;             included for ahdi.prg, and not shdriver.sys).    :
  86. ; 26-May-1988 ml    Added request sense code for use in HDX 3.0    :
  87. ;             for SR444 (Syquest drive).            :
  88. ; ??-Aug-1988 ml  v2.0    Attempted to add code for removable media.    :
  89. ; 07-Sep-1988 ml    Found out that shouldn't move code around too    :
  90. ;             much.  Labels i_sasi and i_sasi1 are used to    :
  91. ;             determine which part of this program will be    :
  92. ;             reserved at Ptermres().  All text and data to    :
  93. ;             be reserved should reside between these two    :
  94. ;             labels.                    :
  95. ; 31-Oct-1988 ml    It seemed to work well.  Now AHDI can handle    :
  96. ;             both removable and non-removable hard disks.    :
  97. ;            It can handle hard disks partitioned in    GEMDOS    :
  98. ;             format or MSDOS 3.x format.              :
  99. ;            Code for executing programs in the AUTO folder     :
  100. ;             and packages in RAM, and code for bringing up    :
  101. ;             AES have been deleted.  Instead, AHDI returns    :
  102. ;             to TOS and let it handle those tasks.        :
  103. ; 01-Dec-1988 ml    Modified _sasi_rw so that it will look for a     :
  104. ;             LONG record number after the device number, if :
  105. ;             the WORD record number == -1.  This allows the    :
  106. ;             caller of Rwabs to address pass 32Mb.        :
  107. ;             Though the underlying routine is the same, the    :
  108. ;             caller has to call Lrwabs from the high level,    :
  109. ;             not Rwabs for this to work.            :
  110. ; 02-Dec-1988 ml    Modified the way we check whether we should jam    :
  111. ;             d7 for further boot before returning to TOS    :
  112. ;             ROMs.  The system build date is being checked    :
  113. ;             instead of the OS version number.  This is    :
  114. ;             necessary because there seems to be confusion    :
  115. ;             about version numbers of some released ROMS.    :
  116. ; 05-Dec-1988 ml    If OS wasn't built before 4/22/1987, when     :
  117. ;             returning to TOS ROMs, jam d7 with the last     :
  118. ;             unit that was processed, instead of magic #.    :
  119. ; 08-Dec-1988 ml    If ospool code is included, make sure 'poolbuf'    :
  120. ;             is the last label in the program to be kept.    :
  121. ;             The code uses the memory after that label as    :
  122. ;             a buffer.  Whatever is after 'poolbuf' will be :
  123. ;             overwritten.                    :
  124. ; 04-Jan-1989 ml    Modified to handle more than 4 partitions per    :
  125. ;             physical unit.  The method used is the same as    :
  126. ;             used in MSDOS 3.3 (ie., by implementing a     :
  127. ;             linked list of logical drives).  There is a     :
  128. ;             type of partition called the EXTENDED GEMDOS    :
  129. ;             PARTITION which is head of the linked list.    :
  130. ;             This new type of partition is specified by the    :
  131. ;             value "XGM" in the p_id field of the partition    :
  132. ;             map.                        :
  133. ; 22-Feb-1989 ml v2.07a    Modified _fdone() and _qdone() to use 200 hz    :
  134. ;             clock for timeout loop.  This would keep the    :
  135. ;             timeout constant over different machines.    :
  136. ; 02-Mar-1989 ml v2.08a Moved pbuf up with regular declarations.  It    :
  137. ;             should stay resident.  Added a cookie pointer    :
  138. ;             for people to check if they have gotten this    :
  139. ;             new version of ahdi.                :
  140. ; 03-Mar-1989 ml    Changed cookie to 'AHDI'.  It will stay that     :
  141. ;             way.  Added version #, a long, right after    :
  142. ;             cookie ptr.                      :
  143. ;             Example: 19890208                :
  144. ;                 1989 - year 1989;            :
  145. ;                 02 - major version #;            :
  146. ;                 08 - minor version #;            :
  147. ; 06-Mar-1989 ml     Enforced 0.005 sec delay between driver calls.    :
  148. ;             Delay only when neccessary before 1st command    :
  149. ;             byte is sent, and update timer when command is    :
  150. ;             done.  New routine _delay().  Update timer     :
  151. ;             code is added in _endcmd().            :
  152. ; 07-Mar-1989 ml    More optimization done on low-level driver.    :
  153. ;             Use registers instead of wdlwdc when accessing    :
  154. ;             DMA registers, etc...                :
  155. ; 09-Mar-1989 ml    Forced driver to stay around even when no drive    :
  156. ;             is found.                    :
  157. ;            Made number of drive to reserve for each ACSI     :
  158. ;             Syquest drive patchable.            :
  159. ;             Magic number $f0ad is used to denote a version    :
  160. ;             with patchable variables.            :
  161. ;             Version number (same as one after the cookie    :
  162. ;             pointer) is stored after magic # $f0ad.    :
  163. ; 10-Mar-1989 ml    Made number of memory chunks to add to ospool    :
  164. ;             patchable.                    :
  165. ; 13-Mar-1989 ml v2.09a    If there is no cartridge in a Syquest drive,    :
  166. ;             return drive not ready, and pass to critical    :
  167. ;             error handler.                    :
  168. ; 29-Mar-1989 ml v2.10a Verion number is now a word, MMmm.        :
  169. ;             (MM - major #; mm - minor #)            :
  170. ;            Added in checks to see if enough memory is    :
  171. ;             allocated for ospool installation and big    :
  172. ;             GEMDOS buffer lists.                :
  173. ; 30-Mar-1989 ml    If there is not enough memory for big GEMDOS    :
  174. ;             buffer lists, make maximum sector size = 512.    :
  175. ;             This guarantees that the regular partitions     :
  176. ;             are still accessible.                :
  177. ;            If there is not enough memory to install amount    :
  178. ;             of OS pool requested. NONE would be installed. :
  179. ;            Variable 'poolbuf' is gone.            :
  180. ; 04-Apr-1989 ml    Sped up media change.  Refer to comments at    :
  181. ;             _sasi_mediach.                    :
  182. ; 11-Apr-1989 ml v3.00    Made version # consistent with HDX and HINSTALL.:
  183. ; 15-May-1989 ml    Initialize sendata buffer to be all 0's every    :
  184. ;             time before _inquiry() is called.        :
  185. ;            Fixed the bug for Dsetpath() (move.l #rootpath    :
  186. ;             instead of move.l rootpath).            :
  187. ; 16-Jun-1989 ml v3.01    Fixed the bug for odd boundary's write.  Should    :
  188. ;             have preserved a1.l since smove() trashes it.    :
  189. ; 25-Sep-1989 ml v3.02a    Modified to handle STACY's hard drive.  If a    :
  190. ;             unit has not been accessed for _n_ minutes,    :
  191. ;             the drive would be "stopped" to save power on    :
  192. ;             on the STACY. _n_ is configurable.        :
  193. ; 26-Sep-1989 ml    The following assumptions are made about STACY-    :
  194. ;             a) there's going to be at most one internal    :
  195. ;                 hard disk in a STACY.            :
  196. ;             b) the internal hard drive, if there is any,     :
  197. ;                 is always ACSI unit 0.            :
  198. ;             c) this driver is used only when there is an    :
  199. ;                 internal hard disk in the STACY.        :
  200. ; 26-Oct-1989 ml v3.02    Officially named 3.02 and out of my hand.    :
  201. ; 24-Apr-1990 ml    Changed default of spin down counter from 5 min    :
  202. ;             to never spin down.  There are programs which    :
  203. ;             talk to the drive directly and don't have the    :
  204. ;             notion of the drive being asleep.        :
  205. ;------------------------------------------------------------------------
  206.  
  207.  
  208. ;
  209. ;------------  Equates and Declarations--------------
  210.  
  211. etv_critic    equ    $404        ; critical error handoff vector
  212. phystop        equ    $42e        ; physical top of memory
  213. flock        equ    $43e        ; FIFO lock variable
  214. _bootdev    equ    $446        ; default boot device
  215. _v_bas_ad    equ    $44e        ; -> base of screen memory
  216. nvbls        equ    $454        ; # lws '_vblqueue' points to
  217. _vblqueue    equ    $456        ; -> vector of ptrs to vbl handlers
  218. hdv_init    equ    $46a        ; hdv_init()    ** UNUSED **
  219. hdv_bpb        equ    $472        ; hdv_bpb(dev)
  220. hdv_rw        equ    $476        ; hdv_rw(rw, buf, count, recno, dev)
  221. hdv_boot    equ    $47a        ; hdv_boot()    ** UNUSED **
  222. hdv_mediach    equ    $47e        ; hdv_mediach(dev)
  223. _bufl        equ    $4b2        ; 2 buffer-list headers
  224. _hz_200        equ    $4ba        ; system 200hz timer
  225. _drvbits    equ    $4c2        ; block device bitVector
  226. _dskbufp    equ    $4c6        ; pointer to common disk buffer
  227. _sysbase    equ    $4f2        ; -> base of OS
  228. pun_ptr        equ    $516        ; number of physical units
  229.  
  230. ;+
  231. ; Restraints 
  232. ;-
  233. MAXUNITS    equ    14        ; max # of log units w/o drv A & B
  234. MAXACSI        equ    8        ; maximum number of ACSI devices
  235. MAXSECTORS    equ    254        ; maximum no. of sectors at one gulp
  236.  
  237. ;+
  238. ; Offsets to ...
  239. ;-
  240. DOSPM        equ    $1be        ; MSDOS boot sect's partition map
  241. DOSSIG        equ    $1fe        ; MSDOS boot sect's signature
  242. HDSIZ        equ    $1c2        ; offset to GEMDOS root sect's 
  243.                     ; hard disk size
  244.  
  245. ;+
  246. ; Constants and Variables
  247. ;-
  248. SIG        equ    $55aa        ; signature for valid MSDOS boot sects
  249. NRETRIES    equ    3        ; #retries-1
  250. MAXNPART    equ    3        ; #partition entries in root sect - 1
  251. BPBLEN        equ    18        ; length of bpb entry in bytes
  252. FATLEN        equ    64        ; max fat size = 64 sectors
  253.                     ; (for 16Mb drive, 2 spc, 512 bps)
  254. SERLEN        equ    3        ; length of a serial # in bytes
  255. CHKDATE        equ    $04221987    ; ROM date for bootstop checking
  256.  
  257. SHIP        equ    0        ; flag to stop ACSI unit 0
  258. UNSHIP        equ    1        ; flag to restart ACSI unit 0
  259.  
  260. ;+
  261. ; BIOS error codes
  262. ;-
  263. EDRVNR        equ    -2        ; driver not ready
  264. EWRITF        equ    -10        ; write fault
  265. EREADF        equ    -11        ; read fault
  266. EWRPRO        equ    -13        ; write on write-protected media
  267. E_CHNG        equ    -14        ; media change detected
  268. CRITRETRY    equ    $00010000    ; "retry" return code
  269.  
  270. ;+
  271. ; SCSI error codes
  272. ;-
  273. DRVNRDY        equ    $4        ; drive not ready
  274. WRTPRTD        equ    $27        ; write on write-protected media
  275. MDMCHGD        equ    $28        ; media change detected
  276.  
  277. ;+
  278. ; Number of bytes per Buffer Control Block (excluding the data block itself)
  279. ;
  280. ; struct_bcb {
  281. ;     struct_bcb    *b_link;    /* 4 bytes */
  282. ;    int        b_neg1;        /* 2 bytes */
  283. ;    int        b_private[5];    /* 10 bytes */
  284. ;    char        *b_bufr;    /* 4 bytes */
  285. ; };
  286. ;
  287. ; For GEMDOS buffer lists.
  288. ;-
  289. BCBLEN        equ    20
  290.  
  291. ;+
  292. ; for extension of os pool
  293. ;-
  294. chunksiz    equ     66        ; #bytes/chunk
  295. chunkno        equ     4        ; chunk# (4 16-byte chunks)
  296.  
  297.  
  298. ;
  299. ;----------------
  300. ;
  301. ;  Entry points:
  302. ;
  303. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  304. ;    +4   Boot entry point (from driver file off of C:)
  305. ;    +8   Reserved for future use
  306. ;    +$C  $F0AD magic number
  307. ;    +$E  version number
  308. ;    +$12 # chunks of ospool to add
  309. ;    +$14 # of sqnpart entries that follows
  310. ;    +$16 first sqnpart entry
  311. ;
  312. ;  if bootloaded, d0 = # bytes allocated by boot code.
  313. ;
  314. i_sasi:    bra    gboot            ; GEMDOS entry-point
  315.     bra    iboot            ; Boot entry-point
  316.     bra    iboot            ; (unused, reserved)
  317.  
  318.  
  319. ;----------------
  320. ;
  321. ;  Patchable variables
  322. ;
  323. magicnum:    dc.w    $f0ad        ; wasn't here in previous releases
  324. vernum:        dc.w    $0302        ; version number
  325. numchunks:    dc.w    128        ; # chunks of ospool to add
  326. minbigsect:    dc.w    512        ; minimum size of a big sector
  327. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  328. minsqnpart:    dcb.b    MAXACSI,1    ; minimum # of logical drives reserved 
  329.                     ;  for removable unit
  330. acsi0idle:    dc.l    0        ; idle time limit b4 ACSI unit0 is spun
  331.                     ;  down (in # of _hz_200 clicks)
  332.                     ;  [infinite -> never spin down]
  333. .even
  334.  
  335. ;----------------
  336. ;
  337. ;  GEMDOS entry;
  338. ;    find amount of memory availble and store in d0.l
  339. ;
  340. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  341.     move.l    4(a2),d0        ; d0 = available memory
  342.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  343.     sub.l    #$0100,d0
  344.     bra    i_sasi1            ; (continue with normal initialization)
  345.  
  346.  
  347. ;----------------
  348. ;
  349. ;  Boot entry;
  350. ;    set "bootloaded", record base address from boot loader, 
  351. ;    and continue with normal boot process.
  352. ;
  353. iboot:    st    bootloaded        ; boot entry-point, set flag
  354.     sub.l    #$1c,d0            ; memory available -= file header
  355.     move.l    a2,baseaddr        ; install base address
  356.                     ; a2 = beginning addr of this block
  357.     bra    i_sasi1            ; (continue with normal initialization)
  358.  
  359.  
  360. ;
  361. ;--------------- Driver State --------------------
  362.  
  363.         dc.b    13,'AHDI : Apr 24 1989 v3.02'
  364.         dc.b    13,10,$bd
  365.         dc.b    'Atari Corp. 1985, 1986, 1987, 1988, 1989, 1990'
  366.         dc.b    13,10,0,$1A
  367. .even
  368.  
  369. _puns:
  370. puns:        dc.w    0        ; # of physical units on user's system
  371.  
  372. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  373. _pun:
  374. pun:        dcb.b    MAXUNITS,0    ; physical unit table
  375. .even
  376.  
  377. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  378. _partstart:
  379. start:        dcb.l    MAXUNITS,0    ; partition start table
  380.  
  381. _cookie:                ; *** DON'T CHANGE ***
  382. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  383.  
  384. _cookptr:
  385. cookptr:    dc.l    0        ; pointer to cookie
  386.  
  387. _versn:
  388. versn:        dc.w    $0302        ; version number: MMmm
  389.  
  390. _maxssz:
  391. maxssz:        dc.w    512        ; maximum sector size handled
  392.  
  393. _idlelmt:                ; idle time b4 spinning down ACSI 0
  394. idlelmt:    dc.l    $ff000000    ;  (in # of _hz_200 clicks)
  395.                     ;  [infinite -> never spin down]
  396.                     ;  high byte set meaning this driver
  397.                     ;  handles spinning down of ACSI 0.
  398.  
  399.         dcb.l    15,0        ; reserved for future use
  400.  
  401. ;+
  402. ; For Stacy
  403. ;-
  404. o_vblq1:    dc.l    0
  405. hdacstm:    dc.l    0        ; ACSI unit 0 last accessed time
  406. shipped:    dc.b    0        ; 0: ACSI unit 0 is _not_ stopped
  407. slock:        dc.b    0        ; 0: can access "shipped"
  408. .even
  409.  
  410. .if    onscreen
  411. screen:        dc.l    0
  412. .endif
  413.  
  414. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  415. mcflgs:    dcb.b    MAXUNITS,2        ; media change flag table
  416. xst:    dcb.b    MAXUNITS,1        ; drive existence flag table
  417. serno:    dcb.b    MAXUNITS*SERLEN,0    ; serial number table
  418. sratio:    dcb.b    MAXUNITS,1        ; log sect size : phys sect size tbl
  419. fatsum:    dcb.b    MAXUNITS*FATLEN,0    ; FAT checksum table
  420. fatst:    dcb.w    MAXUNITS,0        ; starting sector # of last FAT
  421. fatend:    dcb.w    MAXUNITS,0        ; ending sector # of last FAT
  422.  
  423. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  424. memalloc:    dc.l    0        ; total memory available if bootloaded
  425. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  426. tokeep:        dc.l    0        ; amount memory to keep
  427. preadret:    dc.w    0        ; return code from pread
  428.  
  429. cpun:        dc.w    0        ; current physical unit
  430. npart:        dc.w    0        ; number of partitions found
  431. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  432.  
  433. strec:        dc.l    0        ; starting sector to read/write
  434. endrec:        dc.l    0        ; last sector to read/write
  435. stbuf:        dc.l    0        ; starting address of buffer
  436. rmbits:        dc.b    0        ; bit map - 1: unit is removable
  437. scsi:        dc.b    0        ; bit map - 1: embedded SCSI drive
  438.  
  439. _retries:    dc.w    NRETRIES    ; number of retries to do
  440. retrycnt:    dc.w    1        ; retry counter
  441.  
  442. o_bpb:        dc.l    0
  443. o_rw:        dc.l    0
  444. o_mediach:    dc.l    0
  445.  
  446. sendata:    dcb.b    16,0        ; buffer for request sense
  447.  
  448. lastacstm:    dc.l    0        ; controller last accessed time
  449. lastmdctm:    dc.l    0        ; time media change was last called
  450. pbuf:        dc.l    0        ; ptr to start of root sector image
  451. fsiz:        dc.w    0        ; FAT size in sectors
  452. fatrec:        dc.w    0        ; 2nd FAT starting sector
  453. sizr:        dc.w    1        ; ratio of log : phys sector size
  454. temp:        dc.l    0        ; temporary storage
  455. savssp:        dc.l    1        ; (saved SSP)
  456. mcrw:        dc.b    0        ; if TRUE, r/w returns media change
  457. ext:        dc.b    0        ; if =0, not processing ext partition
  458.  
  459. extrt:        dc.l    0        ; starting sector of ext DOS partition
  460. extvol:        dc.l    0        ; offset wrt ext DOS partition
  461. pbpb:        dc.w    0        ; partition # for dev
  462. .even
  463.  
  464.  
  465. ;
  466. ;------------------ Front End ------------------
  467.  
  468. ;----------------
  469. ;
  470. ;  Return pointer to BPB (or NULL)
  471. ;
  472. ;    Synopsis:    LONG hbpb(dev)
  473. ;        WORD dev;    4(sp).w
  474. ;
  475. hbpb:    move.w    4(sp),d0        ; d0 = devno
  476.     clr    d1            ; d1 = 0, physical op not possible
  477.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  478.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  479.     bra.s    check_dev        ; do it
  480.  
  481.  
  482. ;----------------
  483. ;
  484. ;  Read or write logical sectors
  485. ;
  486. ;    Synopsis:    LONG rw(rw, buf, count, recno, dev)
  487. ;        WORD rw;    $4(sp).w
  488. ;        char *buf;    $6(sp).l
  489. ;        WORD count;    $a(sp).w
  490. ;        WORD recno;    $c(sp).w
  491. ;        WORD dev;    $e(sp).w
  492. ;
  493. hrw:    move.w    $e(sp),d0        ; d0 = devno
  494.     move.w    4(sp),d1        ; d1 includes physical device flag
  495.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  496.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  497.     bra.s    check_dev        ; do it
  498.  
  499.  
  500. ;----------------
  501. ;
  502. ;  Check for media change
  503. ;
  504. ;    Synopsis:    LONG mediach(dev)
  505. ;        WORD dev;    4(sp).W
  506. ;
  507. hmediach:
  508.     move.w    4(sp),d0        ; d0 = devno
  509.     clr    d1            ; physical operation not possible
  510.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  511.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  512.  
  513.  
  514. ;----------------
  515. ;
  516. ;  check_dev - use handler, or pass vector through
  517. ;
  518. ;  Passed:    d0.w = device#
  519. ;        d1, bit 3  1=physical operation
  520. ;        a0 ->  old handler
  521. ;        a1 ->  new handler
  522. ;        a5 ->  $0000 (zero-page ptr)
  523. ;
  524. ;  Jumps-to:    (a1) if dev in range for this handler
  525. ;        (a0) otherwise
  526. ;
  527. check_dev:
  528.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  529.     bmi.s    chkd_f            ; if lower, not one of ours
  530.  
  531.     btst    #3,d1            ; is this a physical unit operation?
  532.     beq.s    chkd_a            ; if not, go to chkd_a
  533.  
  534.     cmp    puns,d0            ; compare unit num to num units exist
  535.     bge.s    chkd_f            ; if unit num too big, not one of ours
  536.     bra.s    chkd_s            ; else it IS one of ours
  537.  
  538. chkd_a:    cmp    #MAXUNITS,d0        ; legal logical unit #?
  539.     bge.s    chkd_f            ; if unit num too big, not one of ours
  540.     lea    pun,a2            ; else a2.l = pointer to pun map
  541.     move.b    0(a2,d0.w),d0        ; d0.b = physical unit #
  542.     bmi.s    chkd_f            ; must be positive for a real unit
  543.  
  544. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  545.     st    slock            ; lock the shipped variable
  546.     andi.b    #$0f,d0            ; keep only unit #
  547.     move.b    d0,cpun+1        ; ACSI unit 0?
  548.     beq.s    chkd_b            ; if so, check shipped
  549.     sf    slock            ; else unlock shipped variable
  550.     bra.s    chkd_f            ; follow success vector
  551.  
  552. chkd_b:    tst.b    shipped            ; was hard drive shipped?
  553.     beq.s    chkd_f            ; if not, go on to proceed
  554.     move.l    a0,-(sp)        ; else save success vector
  555.     move.w    #UNSHIP,-(sp)        ; start up the unit
  556.     move.w    d0,-(sp)        ; ACSI unit 0
  557.     bsr    _stunit            ; stunit(physunit, UNSHIP)
  558.     addq.w    #4,sp            ; clean up stack
  559.     sf    shipped            ; ACSI unit 0 not shipped anymore
  560.  
  561. .if    onscreen
  562.     movea.l    screen,a0        ; announce disk is not shipped
  563.     move.l    #0,(a0)            ;   anymore
  564. .endif
  565.  
  566.     move.l    (sp)+,a0        ; restore success vector
  567. chkd_f:    jmp    (a0)            ; do it
  568.  
  569.  
  570. ;
  571. ;------------------ Medium-Level Driver ----------------
  572.  
  573. ;----------------
  574. ;
  575. ;  Return BPB for logical device
  576. ;
  577. ;    Synopsis:    LONG _sasi_bpb(dev)
  578. ;        WORD dev;    $4(sp).w
  579. ;
  580. ;    Returns:    NULL, or a pointer to the BPB buffer
  581. ;
  582. ; 10-21-88    ml.    I am not making a special case for non-removable
  583. ;            hard disk, because if a program uses Allan's
  584. ;            program to force a media change, the program 
  585. ;            should be getting the "Real" AND "New" BPB.
  586. ;            (The old (v1.7 and before) AHDI only index into
  587. ;            the bpbs table and return the pointer, without
  588. ;            actually go and read the boot sector of the dev.)
  589. ;
  590. _sasi_bpb:
  591.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  592. bpbst:    move.w    4(sp),d1        ; d1 = device number
  593.     lea    pun,a0            ; a0 = ptr to pun table
  594.     adda.w    d1,a0            ; a0 = ptr to pun @ dev's entry
  595.     clr.w    d2            ; coerce byte to word
  596.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  597.  
  598.     lea    xst,a1            ; a0 = ptr to drive existence table
  599.     tst.b    (a1,d1.w)        ; does drive exist?
  600.     bne.s    bpbgo            ; if it does, go on normally
  601.                     ; else, see if it really doesn't exist
  602.     movem.w    d1-d2,-(sp)        ; else save registers
  603.     move.w    d2,-(sp)        ; physical unit number
  604.     bsr    testunit        ; verify by doing test unit ready
  605.     addq.l    #2,sp            ; cleanup stack
  606.     movem.w    (sp)+,d1-d2        ; restore registers
  607.     tst.w    d0            ; return good status?
  608.     beq    badbpb            ; if yes, ie. medium has not changed
  609.                     ; therefore, dev still doesn't exist
  610.     moveq    #1,d0            ; else medium may have changed
  611.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  612.     bra.s    bpbst            ; restart procedure
  613.  
  614. bpbgo:    move.w    d2,cpun            ; cpun = pun(dev)
  615.     move.l    _dskbufp,pbuf        ; pbuf = ptr to 2nd half of 1K disk buf
  616.     add.l    #512,pbuf
  617.  
  618. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  619.     move.w    #1,-(sp)        ; return media change if detected
  620.     move.w    cpun,-(sp)        ; physical unit number
  621.     move.l    pbuf,-(sp)        ; buffer to read into
  622.     move.w    #1,-(sp)        ; read in 1 sector
  623.     clr.l    -(sp)            ; from sector 0
  624.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  625.     adda    #14,sp
  626.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  627.     tst    d0            ; pread successful?
  628.     beq.s    bpb0            ; if yes, go on normally
  629.  
  630. bpberr:    cmpi.w    #E_CHNG,d0        ; is media change detected?
  631.     beq.s    bpbchg            ; if so, set mcflgs
  632.                     ; else call up error handler
  633.     move.l    a0,-(sp)        ; save ptr to pun(dev)
  634.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  635.     bsr    critic            ; call up critical error handler
  636.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  637.     cmpi.l    #CRITRETRY,d0        ; retry?
  638.     beq.s    bpb00            ; if so, go and try again
  639.     bra    badbpb            ; else return no BPB
  640.  
  641. bpbchg:    move.b    #1,d0            ; d0.b = media may be changed
  642.     move.w    4(sp),d1        ; d1.w = device number
  643.     move.b    cpun+1,d2        ; d2.b = physical unit number
  644.     bsr    s_mc_xst        ; go set mcflgs and xst flags
  645.     bra    bpbst            ; restart procedure
  646.  
  647. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  648.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  649. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  650.     bne.s    bpb2
  651.     addq.w    #1,pbpb
  652.     bra.s    bpb1
  653.  
  654. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  655.     movea.l    pbuf,a0            ; a0 = ptr to beginning of root sector
  656.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  657.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  658.     bsr    dosbpb            ; else, handle it the DOS way
  659.     bra.s    bpb4            ; else, go get the bpb
  660. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  661.     bsr    gembpb            ; handle it the GEMDOS way
  662. bpb4:    tst.w    d0            ; successful?
  663.     beq.s    bpbnf            ; if =0, no valid BPB found
  664.     bpl.s    bpb5            ; if +ive, valid BPB found
  665.     cmpi.w    #E_CHNG,d0        ; else media changed?
  666.     beq.s    bpbchg            ; if so, restart procedure
  667.     bra.s    badbpb            ; else no BPB found
  668.                     ; partition not found
  669. bpbnf:    lea    xst,a0            ; a0 = ptr to drive existence table
  670.     move.w    4(sp),d0        ; d0 = dev number
  671.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  672.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  673.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  674.     bra.s    badbpb            ; can't find such a partition
  675.  
  676. bpb5:    move.l    d1,-(sp)        ; start_sector
  677.     move.w    8(sp),-(sp)        ; dev number
  678.     bsr    getbpb            ; getbpb(dev, start_sector)
  679.     addq.l    #6,sp            ; clean up stack
  680.     tst.l    d0            ; getbpb successful?
  681.     bpl.s    ret2calr        ; if so, return ptr to bpb
  682.     cmpi.w    #E_CHNG,d0        ; media changed?
  683.     beq    bpbchg            ; if so, restart procedure
  684. badbpb:    moveq    #0,d0            ; return no bpb found
  685. ret2calr:                ; return to caller
  686.     andi.b    #$0f,cpun+1        ; accessing ACSI unit 0?
  687.     bne.s    rrts            ; if not, really return now
  688.     move.l    _hz_200,hdacstm        ; else initialize last accessed time
  689.     sf    slock            ; unlock the shipped variable
  690. rrts:    rts
  691.  
  692.  
  693. ;
  694. ;+
  695. ; dosbpb - find the DOS partition that corresponds to the requested
  696. ;       logical drive
  697. ; Passed:
  698. ;    a0 = buffer address for root sector
  699. ;    d1 = number of entries in partition map
  700. ;
  701. ; Assumed:
  702. ;    pbpbs = partition being looked for
  703. ;
  704. ; Returns:
  705. ;    d0.b = 0        if partition not found
  706. ;         = negative #    some kind of error
  707. ;         = positive #    system indicator of the partition
  708. ;    d1.l = starting sector of the partition (if it is found)
  709. ;-
  710. dosbpb:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  711. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  712.     sf    ext            ; not dealing with ext partition
  713.     bsr    fdpart            ; find a partition
  714.     tst.b    d0            ; found any?
  715.     beq.s    dbpba            ; not a valid partition
  716.     cmpi.b    #5,d0            ; extended partition?
  717.     bne.s    dbpb1            ; if not, it's a regular partition
  718.     st    ext            ; else, it's an extended partition
  719.     move.l    #0,extvol        ; offset from start of partition = 0
  720.     move.l    d1,extrt        ; starting sector # of ext partition
  721. dbpbx:    bsr    fdnxt            ; find next logical drive
  722.     tst.b    d0            ; found any?
  723.     beq.s    dbpba            ; no logical drive found
  724.     bmi.s    dbpb2            ; error returned
  725.     cmpi.b    #5,d0            ; extended volume?
  726.     beq.s    dbpbx            ; if so, go find next logical drive
  727. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  728.     bpl.s    dbpb3            ; if not, continue the search
  729. dbpb2:    addq.l    #8,sp            ; else clean up stack
  730.     move.w    #0,bfat            ; assume partition has 12-bit fat
  731.     cmpi.b    #1,d0            ; 12-bit fat?
  732.     beq.s    dbpb22            ; if so, return
  733.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  734. dbpb22:    bra.s    dbpbr            ; and return
  735. dbpb3:    tst.b    ext            ; clun is in ext partition?
  736.     bne.s    dbpbx            ; if so, go find next ext vol
  737. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  738.     adda    #16,a0            ; index to next entry in pmap
  739.     dbra    d1,dbpb0
  740.     moveq    #0,d0            ; partition not found!
  741. dbpbr:    rts
  742.  
  743.     
  744. ;+
  745. ; fdpart - find a DOS partition.
  746. ;
  747. ; Passed:
  748. ;    a0 = address to partition entry
  749. ;
  750. ; Returns:
  751. ;    d0.b = 0        partition is not valid
  752. ;         = positive    #    partition is a valid partition
  753. ;           (this is the system indicator of the partition)
  754. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  755. ;         = starting sector # of extended partition (if d0.b = 5)
  756. ;-
  757. fdpart:    tst.l    12(a0)            ; partition's size?
  758.     beq.s    fdp0            ; if =0, not valid
  759.  
  760.     move.b    4(a0),d0        ; d0 = system indicator
  761.     beq.s    fdpr            ; if =0, not valid
  762.  
  763.     cmpi.b    #4,d0            ; if =4, valid
  764.     beq.s    fdp1
  765.  
  766.     cmpi.b    #1,d0            ; if =1, valid
  767.     beq.s    fdp1
  768.  
  769.     cmpi.b    #5,d0            ; if =5, valid
  770.     beq.s    fdp1
  771.  
  772. fdp0:    moveq    #0,d0            ; else, not valid
  773.     bra.s    fdpr
  774.  
  775. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  776.     ror.w    #8,d1            ; swap hi and lo byte of high word
  777.     swap    d1            ; swap hi and lo word
  778.     ror.w    #8,d1            ; swap hi and lo byte of low word
  779. fdpr:    rts
  780.  
  781.  
  782. ;+
  783. ; fdnxt - find a logical drive in the extended DOS partition
  784. ;
  785. ; Passed:
  786. ;    d0.b = (= 5 if a new extended volume was found)
  787. ;           (= 0 if nxtdrv was successful for last logical drive found)
  788. ;    d1.l = starting sector # of this extended volume
  789. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  790. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  791. ;
  792. ; Assumes:
  793. ;    cpun = current physical unit #
  794. ;    extrt = starting sector # of extended DOS partition
  795. ;    extvol = offset from start of extended DOS partition (in sectors)
  796. ;
  797. ; Returns:
  798. ;    d0.b = 0        no logical drive found
  799. ;         = positive #    valid logical drive found
  800. ;           (this is the system indicator of the logical drive)
  801. ;         = negative #    error occured
  802. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  803. ;         = starting sector # of next extended volume (if d0.b = 5)
  804. ;-
  805. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  806.     bne.s    fdnxt0        ; if not, search for one
  807.     move.w    #1,-(sp)    ; return media change if detected
  808.     move.w    cpun,-(sp)    ; physical unit number
  809.     move.l    _dskbufp,-(sp)    ; buffer to read into
  810.     move.w    #1,-(sp)    ; read in 1 sector
  811.     move.l    d1,-(sp)    ; from beginning of extended volume
  812.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  813.     adda    #14,sp        ; cleanup stack
  814.     tst.w    d0        ; pread successful?
  815.     bne    fdnxtr        ; if so, return
  816.     
  817.     movea.l    _dskbufp,a0    ; else, 
  818.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  819.     bne.s    fdnxtr        ; if not, return no drive found
  820.                 ; (d0 already set by pread)
  821.     adda.w    #DOSPM-16,a0    ; a0 = ptr to 1st entry in log drive map
  822.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  823.  
  824. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  825.     bmi.s    fdnxt1        ; if not, return
  826.  
  827.     adda    #16,a0        ; a0 = ptr to entry to be examined
  828.     tst.l    12(a0)        ; partition size's?
  829.     beq.s    fdnxt0        ; if =0, not valid
  830.  
  831.     move.b    4(a0),d0    ; d0 = system indicator
  832.     beq.s    fdnxt0        ; if =0, not valid
  833.  
  834.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  835.     beq.s    fdnxt0        ; if =0, not valid
  836.     ror.w    #8,d1        ; swap hi and lo byte of high word
  837.     swap    d1        ; swap hi and lo word
  838.     ror.w    #8,d1        ; swap hi and lo byte of low word
  839.  
  840.     cmpi.b    #4,d0        ; if =4,
  841.     beq.s    fdnxt2        ; valid logical drive found
  842.  
  843.     cmpi.b    #1,d0        ; if =1,
  844.     beq.s    fdnxt2        ; valid logical drive found
  845.  
  846.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  847.     bne.s    fdnxt0        ; else, not valid
  848.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  849.     bra.s    fdnxt3
  850.  
  851. fdnxt1:    moveq    #0,d0        ; return no drive found
  852.     bra.s    fdnxtr
  853.  
  854. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  855. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  856. fdnxtr:    rts
  857.  
  858.  
  859. ;
  860. ;+
  861. ; gembpb - find the GEMDOS partition that corresponds to the requested
  862. ;       logical drive.
  863. ; Passed:
  864. ;    a0 = buffer address for root sector
  865. ;    d1 = number of entries in partition map
  866. ;
  867. ; Assumed:
  868. ;    pbpbs = partition being looked for
  869. ;
  870. ; Returns:
  871. ;    d0.b = 0        if partition not found
  872. ;         = negative #    some kind of error
  873. ;         = positive #    system indicator of the partition
  874. ;    d1.l = starting sector of the partition (if it is found)
  875. ;-
  876. gembpb:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  877.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  878.     beq.s    gbpb4            ; if =0, no drive will exist
  879. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  880.     sf    ext            ; not dealing with ext partition
  881.     bsr    fgpart            ; find partitions
  882.     tst.b    d0            ; found any?
  883.     beq.s    gbpba            ; not a valid partition
  884.     cmpi.b    #'X',d0            ; extended partition?
  885.     bne.s    gbpb1            ; if not, it's a regular partition
  886.     st    ext            ; else, it's an extended partition
  887.     move.l    #0,extvol        ; offset from start of partition = 0
  888.     move.l    d1,extrt        ; starting sector # of ext partition
  889. gbpbx:    bsr    fgnxt            ; find next logical drive
  890.     tst.b    d0            ; found any?
  891.     beq.s    gbpba            ; no logical drive found
  892.     bmi.s    gbpb2            ; error returned
  893.     cmpi.b    #'X',d0            ; extended volume?
  894.     beq.s    gbpbx            ; if so, go find next logical drive
  895. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  896.     bpl.s    gbpb3            ; if not, continue the search
  897. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  898.     bra.s    gbpbr            ; and return
  899. gbpb3:    tst.b    ext            ; clun is in ext partition?
  900.     bne.s    gbpbx            ; if so, go find next ext vol
  901. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  902.     adda    #12,a0            ; index to next entry in pmap
  903.     dbra    d1,gbpb0
  904. gbpb4:    moveq    #0,d0            ; partition not found!
  905. gbpbr:    rts
  906.  
  907.  
  908. ;+
  909. ; fgpart - find a GEMDOS partition.
  910. ;
  911. ; Passed:
  912. ;    a0 = address to partition entry
  913. ;
  914. ; Returns:
  915. ;    d0.b = 0        partition is not valid
  916. ;         = positive    #    partition is a valid partition
  917. ;           (this is the first byte in p_id of the partition)
  918. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  919. ;         = starting sector # of extended partition (if d0.b = 'X')
  920. ;-
  921. fgpart:    tst.b    (a0)            ; check the valid partition flag
  922.     beq.s    fgp2            ; if =0, not valid
  923.  
  924.     tst.l    8(a0)            ; partition's size?
  925.     beq.s    fgp2            ; if =0, not valid
  926.  
  927.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  928.     bne.s    fgp0            ; for REGULAR partition
  929.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  930.     bne.s    fgp0
  931.     cmpi.b    #'M',3(a0)
  932.     beq.s    fgp3
  933.  
  934. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  935.     bne.s    fgp1            ; for BIG partition
  936.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  937.     bne.s    fgp1
  938.     cmpi.b    #'M',3(a0)
  939.     beq.s    fgp3
  940.  
  941. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  942.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  943.     cmpi.b    #'G',2(a0)        ; partition
  944.     bne.s    fgp2            ; (ie., partition with
  945.     cmpi.b    #'M',3(a0)        ;  a linked list of
  946.     beq.s    fgp3            ;  logical drives)
  947.  
  948. fgp2:    moveq    #0,d0            ; else, not valid
  949.     bra.s    fgpr
  950.  
  951. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  952.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  953. fgpr:    rts
  954.  
  955.  
  956. ;+
  957. ; fgnxt - find a logical drive in the extended GEMDOS partition
  958. ;
  959. ; Passed:
  960. ;    d0.b = (= 'X' if a new extended volume was found)
  961. ;           (= 0 if nxtdrv was successful for last logical drive found)
  962. ;    d1.l = starting sector # of this extended volume
  963. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  964. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  965. ;
  966. ; Assumes:
  967. ;    cpun = current physical unit #
  968. ;    extrt = starting sector # of extended GEMDOS partition
  969. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  970. ;
  971. ; Returns:
  972. ;    d0.b = 0        no logical drive found
  973. ;         = positive #    valid logical drive found
  974. ;           (this is the first byte of p_id of the logical drive)
  975. ;         = negative #    error occured
  976. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  977. ;         = starting sector # of next extended volume (if d0.b = 'X')
  978. ;-
  979. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  980.     bne.s    fgnxt0        ; if not, search for one
  981.     move.w    #1,-(sp)    ; return media change if detected
  982.     move.w    cpun,-(sp)    ; physical unit number
  983.     move.l    _dskbufp,-(sp)    ; buffer to read into
  984.     move.w    #1,-(sp)    ; read in 1 sector
  985.     move.l    d1,-(sp)    ; from beginning of extended volume
  986.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  987.     adda    #14,sp        ; cleanup stack
  988.     tst.w    d0        ; pread successful?
  989.     bne    fgnxtr        ; if not, return error
  990.  
  991.     movea.l    _dskbufp,a0    ; a0 = ptr to partition map
  992.     adda.w    #HDSIZ+4-12,a0    ; a0 = ptr to 1st entry in log drive map
  993.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  994.  
  995. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  996.     bmi.s    fgnxt3        ; if not, return
  997.  
  998.     adda    #12,a0        ; a0 = ptr to entry to be examined
  999.     tst.l    8(a0)        ; partition size's?
  1000.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  1001.  
  1002.     tst.b    (a0)        ; check the valid partition flag
  1003.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  1004.  
  1005.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  1006.  
  1007.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  1008.     bne.s    fgnxt1        ; for REGULAR partition
  1009.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  1010.     bne.s    fgnxt1
  1011.     cmpi.b    #'M',3(a0)
  1012.     beq.s    fgnxt4
  1013.  
  1014. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  1015.     bne.s    fgnxt2        ; for BIG partition
  1016.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  1017.     bne.s    fgnxt2
  1018.     cmpi.b    #'M',3(a0)
  1019.     beq.s    fgnxt4
  1020.  
  1021. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  1022.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  1023.     cmpi.b    #'G',2(a0)    ; partition
  1024.     bne.s    fgnxt3        ; (ie., partition with
  1025.     cmpi.b    #'M',3(a0)    ;  a linked list of
  1026.     bne.s    fgnxt0        ;  logical drives)
  1027.  
  1028.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  1029.     bra.s    fgnxt5
  1030.  
  1031. fgnxt3:    moveq    #0,d0        ; return no drive found
  1032.     bra.s    fgnxtr
  1033.  
  1034. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  1035. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  1036.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  1037. fgnxtr:    rts
  1038.  
  1039.  
  1040. ;
  1041. ;--------------
  1042. ;
  1043. ; getbpb(dev, sectorno)
  1044. ; WORD dev;        4(sp).w
  1045. ; LONG sectorno;    6(sp).l
  1046. ;
  1047. ; Assume -
  1048. ;    cpun contains physical unit number of dev
  1049. ;
  1050. getbpb:    move.w    #1,-(sp)        ; return media change if detected
  1051.     move.w    cpun,-(sp)        ; physical unit
  1052.     move.l    _dskbufp,-(sp)        ; buffer
  1053.     move.w    #1,-(sp)        ; 1 sector
  1054.     move.l    $10(sp),-(sp)        ; sector # of boot sector
  1055.     bsr    pread            ; pread(bootsect, 1, buf, phys#, flag)
  1056.     adda    #14,sp            ; clean up stack
  1057.     tst.w    d0            ; any trouble reading?
  1058.     beq.s    getb0            ; if no, go on normally
  1059.     cmpi.w    #EREADF,d0        ; was it a read error?
  1060.     beq.s    getb9            ; if it is, retry
  1061.     cmpi.w    #EDRVNR,d0        ; was it drive not ready?
  1062.     bne    getb8            ; if not, return
  1063.                     ; else let user retry
  1064. getb9:    move.w    4(sp),d1        ; d1 = drive # excluding A: and B:
  1065.     bsr    critic
  1066.     cmpi.l    #CRITRETRY,d0        ; retry?
  1067.     bne    getb7            ; if not, return
  1068.     bra.s    getbpb            ; else read again
  1069.  
  1070. getb0:    movea.l    _dskbufp,a0        ; a0 = ptr to boot sector image
  1071.     movea.l    #bpbs,a2        ; a2 = ptr to bpb
  1072.  
  1073.     move.w    #$0b,d0
  1074.     bsr    getlhw
  1075.     cmp.w    maxssz,d0        ; is sector size too big?
  1076.     bhi    getb7            ; if it is, can't handle it
  1077.     move.w    d0,(a2)+        ; =byt/sec
  1078.     beq    getb7            ; if =0, bad data
  1079.     move.w    d0,d1
  1080.     divu    #512,d0            ; d0.b = ratio log : phys sector size
  1081.     move.w    d0,sizr            ; save the ratio
  1082.  
  1083.     clr.w    d0
  1084.     move.b    $d(a0),d0
  1085.     move.w    d0,(a2)+        ; =sec/cluster
  1086.     beq    getb7            ; if =0, bad data
  1087.  
  1088.     mulu    d1,d0
  1089.     move    d0,(a2)+        ; =byt/cluster
  1090.  
  1091.     move    #$11,d0
  1092.     bsr    getlhw            ; number of directory entries
  1093.     tst    d0            ; num o' entries ?= 0
  1094.     beq    getb7            ; if so, bad data
  1095.     mulu    #32,d0            ; size of each entry
  1096.     divu    d1,d0            ; number of sectors required
  1097.     move.l    d0,d1
  1098.     swap    d1
  1099.     tst    d1
  1100.     beq.s    getb1
  1101.     addq    #1,d0            ; round up
  1102. getb1:    move    d0,(a2)+        ; =rdlen
  1103.     move    d0,d2
  1104.  
  1105.     move    #$16,d0
  1106.     bsr    getlhw
  1107.     move    d0,(a2)+        ; =FATsize
  1108.     beq    getb7            ; if =0, bad data
  1109.     move    d0,d1
  1110.     move    d0,fsiz            ; save FAT size
  1111.  
  1112.     move    #$e,d0
  1113.     bsr    getlhw            ; number of reserved sectors
  1114.     add    d1,d0
  1115.     move    d0,(a2)+        ; =2nd FAT start
  1116.     move    d0,fatrec        ; save 2nd FAT start 
  1117.  
  1118.     add    d1,d0            ; plus size of second fat
  1119.     add    d2,d0            ; plus rdlen
  1120.     move    d0,(a2)+        ; = data start
  1121.     move    d0,d2            ; save start of data
  1122.  
  1123.     move    #$13,d0
  1124.     bsr    getlhw            ; number of sectors on media
  1125.     sub    d2,d0            ; subtract # used by FATs,dir,boot
  1126.     beq    getb7            ; if =0, bad data
  1127.     clr.l    d1
  1128.     move    d0,d1
  1129.     clr    d0
  1130.     move.b    $d(a0),d0        ; number of sectors/cluster
  1131.     divu    d0,d1            ; rounding down
  1132.     move    d1,(a2)+        ; =number of clusters
  1133.     move    bfat,(a2)        ; =flags, 12 or 16 bit fats
  1134.  
  1135.     move.w    sizr,d2            ; d2 = current sector size ratio
  1136.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1137.     move.w    4(sp),d0        ; d0 = drive number
  1138.     move.b    d2,(a1,d0.w)        ; update sector size ratio in table
  1139.  
  1140.     move.w    cpun,d1            ; d1 = physical unit #
  1141.     btst.b    d1,rmbits        ; is unit removable?
  1142.     beq    getb6            ; if not, can skip the fat checksum
  1143.  
  1144.     lea    serno,a1        ; a1 = ptr to table of serial #s
  1145.     mulu.w    #SERLEN,d0        ; dev# * SERLEN to index into table
  1146.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1147.     move.w    #SERLEN-1,d1        ; length of serial # - 1
  1148. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1149.     dbra    d1,getb2
  1150.  
  1151.     lea    fatsum,a2        ; a2 = ptr to FAT check sum table
  1152.     move.w    4(sp),d0        ; d0 = dev number
  1153.     mulu    #FATLEN,d0        ; d0*FATLEN = to index into table
  1154.     adda.l    d0,a2            ; a2 = ptr to FAT check sum tbl of dev
  1155.  
  1156.     move.w    fatrec,d0        ; d0 = log starting sector of 2nd FAT
  1157.     mulu    d2,d0            ; (in 512-byte sectors)
  1158.     movea.l    $6(sp),a1        ; a1 = starting sector of drive
  1159.     adda.l    d0,a1            ; a1 = phys starting sector of 2nd FAT
  1160.  
  1161.     move.w    fsiz,d1            ; d1 = # FAT sectors to read
  1162.     subq.l    #1,d1            ;    = FAT size - 1
  1163.  
  1164. getb3:    move.w    sizr,d2            ; d2 = count per FAT sector
  1165.     subq.w    #1,d2
  1166.      clr.l    temp            ; initialize the sum
  1167. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1168.     move.w    #1,-(sp)        ; return media change if detected
  1169.     move.w    cpun,-(sp)        ; physical unit
  1170.     move.l    a0,-(sp)        ; buffer (in _dskbufp)
  1171.     move.w    #1,-(sp)        ; read 1 phys sector
  1172.     move.l    a1,-(sp)        ; from sector a1
  1173.     bsr    pread            ; pread()
  1174.     adda    #14,sp            ; clean up stack
  1175.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1176.     tst.w    d0            ; pread successful?
  1177.     beq    getb5            ; if so, go on normally
  1178.     cmpi.w    #EREADF,d0        ; read error?
  1179.     beq.s    getba            ; if so, retry
  1180.     cmpi.w    #EDRVNR,d0        ; drive not ready?
  1181.     bne    getb8            ; if not, return
  1182.  
  1183. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1184.     move.w    24(sp),d1        ; d1 = drive # excluding A: and B:
  1185.     bsr    critic            ; critical error handler
  1186.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1187.     cmpi.l    #CRITRETRY,d0        ; retry?
  1188.     beq.s    getb4            ; if so, try again
  1189.     bra    getb7            ; else return
  1190.  
  1191. getb5:    bsr    bsum            ; add up values in the sector
  1192.     addq    #1,a1            ; get ready for next sector
  1193.     dbra    d2,getb4        ; until one logical FAT sector is done
  1194.  
  1195.     bsr    csum            ; find the checksum
  1196.     move.b    d0,(a2)+        ; update checksum for this FAT sector
  1197.     dbra    d1,getb3        ; until all sectors are checked
  1198.  
  1199. getb6:    move.w    $4(sp),d0        ; d0 = dev number
  1200.     lea    mcflgs,a0        ; load address of mcflgs table
  1201.     clr.b    (a0,d0.w)        ; clear mcflg for dev
  1202.  
  1203.     lea    xst,a0            ; a0 = ptr to drive existence table
  1204.     move.b    #2,(a0,d0.w)        ; dev definitely exists
  1205.  
  1206.     lea    fatst,a0        ; a0 = ptr to FAT start sector table
  1207.     asl.w    #1,d0            ; offset = dev# * 2 (tbl of words)
  1208.     move    fatrec,(a0,d0.w)    ; update FAT starting sect#
  1209.  
  1210.     lea    fatend,a0        ; a0 = ptr to FAT end sector table
  1211.     move.w    fatrec,d1        ; d1 = fatend(dev)
  1212.     add.w    fsiz,d1            ;    = fatrec + fsiz - 1
  1213.     subq.w    #1,d1    
  1214.     move.w    d1,(a0,d0.w)        ; fatend(dev) = fatrec + fsiz - 1
  1215.  
  1216.     lea    start,a0        ; a0 = ptr to beginning of start table
  1217.     asl.w    #1,d0            ; offset = dev# * 2 * 2 (tbl of longs)
  1218.     move.l    $6(sp),(a0,d0.w)    ; update starting sect# of dev
  1219.  
  1220.     move.l    #bpbs,d0        ; no errors, return ptr to BPB
  1221.     bra.s    getb8            ; return
  1222.  
  1223. getb7:    moveq    #-1,d0            ; error
  1224. getb8:    rts
  1225.  
  1226.  
  1227. ;+
  1228. ; WORD getlhw(d0=offset)
  1229. ; returns word (low,high) from 0(D0,A0)
  1230. ;-
  1231.  
  1232. getlhw:    move    d1,-(sp)        ; preserve d1
  1233.     move.b    1(a0,d0.w),d1
  1234.     lsl.w    #8,d1
  1235.     move.b    0(a0,d0.w),d1
  1236.     move    d1,d0
  1237.     move    (sp)+,d1
  1238.     rts
  1239.  
  1240.  
  1241. ;+
  1242. ; bsum
  1243. ;
  1244. ; Passed:
  1245. ;    a0 = starting address of buffer to be summed
  1246. ;    temp.l = current sum
  1247. ;
  1248. ; Function:
  1249. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1250. ;    - save the sum in temp.l
  1251. ;
  1252. ; Algorithm for check summing the FAT:
  1253. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1254. ;    - if the sum is non-zero, EOR the high word     (in csum)
  1255. ;      with the low word of the 4-byte result
  1256. ;    - now take this 2-byte result, and EOR its high    (in csum)
  1257. ;      byte with its low byte to get the final 1-byte
  1258. ;      result
  1259. ;-
  1260. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1261.     move.l    temp,d0            ; d0 = current sum
  1262.     move    #127,d1            ; count
  1263. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1264.     dbra    d1,bsum0        ; until all bytes are added
  1265.     move.l    d0,temp            ; temp.l = new sum
  1266.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1267.     rts
  1268.  
  1269.  
  1270. ;+
  1271. ; csum
  1272. ; (a) EOR the high word with the low word of temp.l
  1273. ; (b) then EOR the high byte with the low byte of result of (a)
  1274. ;
  1275. ; Returns:
  1276. ;    d0.b = checksum
  1277. ;-
  1278. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1279.     eor.w    d0,temp            ; exclusive-or low and high word
  1280.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1281.     eor.b    d0,temp            ; exclusive-or low and high byte
  1282.     move.b    temp,d0
  1283.     rts                ; d0.b = checksum
  1284.  
  1285.  
  1286. ;
  1287. ;----------------
  1288. ;
  1289. ;  Read/Write sectors
  1290. ;
  1291. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1292. ;        WORD rw        4(sp).w        ; non-zero -> write
  1293. ;        char buf    6(sp).l
  1294. ;        WORD count    $a(sp).w
  1295. ;        WORD recno    $c(sp).w
  1296. ;        WORD dev    $e(sp).w
  1297. ;        WORD lrecno    $10(sp).l    ; optional
  1298. ;-
  1299.  
  1300. ; stack frame offsets
  1301. xrw    equ    8
  1302. xbuf    equ    10
  1303. xcount    equ    14
  1304. xrecno    equ    16
  1305. xdev    equ    18
  1306. xlrecno    equ    20
  1307.  
  1308. _sasi_rw:
  1309. _ahdi_rw:
  1310.     link    a6,#0            ; create a frame pointer
  1311.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1312.     move.w    xrw(a6),d0        ; r/w and flags word
  1313.     andi.b    #$a,d0            ; phys op?  ignore media change?
  1314.     bne    ahrw1            ; yes, go ahead and do r/w
  1315.                     ; else check for media change
  1316.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1317.     adda.w    xdev(a6),a1        ; a1 = ptr to dev's sector size ratio
  1318.     move.b    (a1),sizr+1        ; sizr = current sector size ratio
  1319.                     ;     (coerced to word)
  1320.     lea    mcflgs,a0        ; a0 = ptr to mcflgs of drive
  1321.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1322.     move.b    (a0),d0            ; d0 = mcflg of dev
  1323.     beq    ahrw1            ; if media definitely not, go do r/w
  1324.  
  1325.     cmpi.b    #2,d0            ; is media definitely changed?
  1326.     beq    retmc            ; if yes, return media has changed
  1327.  
  1328.     sf    mcrw            ; mcrw = FALSE
  1329.     lea    pun,a1            ; a1 = ptr to pun table
  1330.     adda.w    xdev(a6),a1        ; a1 = ptr to pun dev belongs to
  1331.     move.b    (a1),cpun+1        ; cpun = pun of dev
  1332.  
  1333. chkmc:    lea    start,a1        ; a1 = ptr to start table
  1334.     move.w    xdev(a6),d0        ; d0 = drive #
  1335.     add.w    d0,d0            ; d0*2*2 (index into tbl of longs)
  1336.     add.w    d0,d0
  1337.     movea.l    (a1,d0.w),a1        ; a1 = dev starting sector
  1338.  
  1339.     move.w    #1,-(sp)        ; return media change if detected
  1340.     move.w    cpun,-(sp)        ; physical unit number
  1341.     move.l    _dskbufp,-(sp)        ; buffer
  1342.     move.w    #1,-(sp)        ; 1 sector
  1343.     move.l    a1,-(sp)        ; dev starting sector
  1344.     bsr    pread            ; try to read dev's boot sector
  1345.     adda    #14,sp            ; clean up stack
  1346.     tst.w    d0            ; pread successful?
  1347.     beq.s    chkser            ; yes, go check serial number
  1348.  
  1349.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1350.     bne.s    rderr1            ; if not, assume it's read error
  1351.  
  1352. mcchg:    move.b    #1,d0            ; d0.b = 1 (may be changed)
  1353.     move.w    xdev(a6),d1        ; d1.w = drive # excluding A: and B:
  1354.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1355.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1356.     bra.s    chkmc            ; then try again
  1357.  
  1358. rderr1:    move.w    xdev(a6),d1        ; device number
  1359.     bsr    critic            ; call critical error handler
  1360.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1361.     beq.s    chkmc            ; if yes, go back and try it
  1362.     bra    ahrw7            ; else return
  1363.  
  1364. chkser:    lea    serno,a1        ; a1 = ptr to serial #s table
  1365.     move.w    xdev(a6),d0        ; d0 = dev number
  1366.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1367.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1368.  
  1369.     move.l    _dskbufp,a2        ; a2 = ptr to buffer
  1370.     addq.w    #8,a2            ; a2 = ptr to serial # read
  1371.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1372. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1373.     bne    ismc            ; no, media has changed
  1374.     dbra    d0,cmpser        ; compare next byte of serial #
  1375.                     ; serial # hasn't changed, try FAT
  1376.     move.w    xdev(a6),d0        ; d0 = dev number
  1377.     lea    fatsum,a1        ; a1 = ptr to fat checksum table
  1378.     move.w    #FATLEN,d1        ; d1.w = index into table
  1379.     mulu    d0,d1
  1380.     adda.l    d1,a1            ; a1 = ptr to fat checksum of dev
  1381.  
  1382.     add.w    d0,d0            ; d0*2 = index into table of words
  1383.     lea    fatst,a2        ; a2 = ptr to FAT start table
  1384.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1385.  
  1386.     lea    fatend,a2        ; a2 = ptr to FAT end table
  1387.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1388.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1389.  
  1390.     lea    start,a2        ; a2 = ptr to start table
  1391.     add.w    d0,d0            ; d0*2*2 = index into table of longs
  1392.     movea.l    (a2,d0.w),a2        ; a2 = start sector of dev
  1393.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1394.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1395.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1396.  
  1397.     movea.l    _dskbufp,a0        ; a0 = ptr to buffer
  1398. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1399.     subq.w    #1,d2            ; d2 - 1 = counter
  1400.     clr.l    temp            ; initialize sum
  1401. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a1, a2
  1402.     move.w    #1,-(sp)        ; return media change if detected
  1403.     move.w    cpun,-(sp)        ; physical unit number
  1404.     move.l    a0,-(sp)        ; buffer
  1405.     move.w    #1,-(sp)        ; 1 sector
  1406.     move.l    a2,-(sp)        ; at sector a2
  1407.     bsr    pread            ; try to read this FAT sector
  1408.     adda    #14,sp            ; clean up stack
  1409.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, a0, a1, a2
  1410.     tst.w    d0            ; pread successful?
  1411.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1412.                     ; else check if it's media change
  1413.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1414.     beq    mcchg            ; if so, go test media change again
  1415.                     ; else assume it's read error
  1416.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1417.     move.w    xdev(a6),d1        ; drive number
  1418.     bsr    critic
  1419.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1420.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1421.     beq.s    cfat0            ; if yes, go back and try it
  1422.     bra    ahrw7            ; else return
  1423.  
  1424. chkfat:    bsr    bsum            ; if ok, sum the sector
  1425.     addq    #1,a2            ; ready for try next sector
  1426.     dbra    d2,cfat0        ; until one FAT sector is summed
  1427.  
  1428.     bsr    csum            ; find the checksum
  1429.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1430.     bne    ismc            ; if no match, media has changed
  1431.     dbra    d1,cmpfat        ; until all sectors are checked
  1432.  
  1433.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1434.     adda.w    xdev(a6),a0        ; a0 = ptr to mcflg of drive
  1435.     clr.b    (a0)            ; clear mcflg for dev
  1436.  
  1437. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1438.     beq    ahrw6            ; if =0, done
  1439.  
  1440.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1441.     bne.s    ahrw9            ; if not, we have a word record #
  1442.     move.l    xlrecno(a6),a1        ; a1.l = start record #
  1443.     bra.s    ahrwa
  1444. ahrw9:    moveq    #0,d0            ; coerce to long
  1445.     move.w    xrecno(a6),d0        ; d0.l = recno
  1446.     movea.l    d0,a1            ; a1.l = start record #
  1447.  
  1448. ahrwa:    move.l    a1,strec        ; save first sector to r/w
  1449.     moveq    #0,d1            ; coerce to long
  1450.     move.w    xcount(a6),d1        ; d1.l = #sectors to r/w
  1451.     adda.l    d1,a1            ; a1.l = last sector to r/w
  1452.     subq.w    #1,a1            ;      = first sector + count - 1
  1453.     move.l    a1,endrec        ; save last sector to r/w
  1454.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1455.  
  1456.     move.l    strec,d1        ; d1.l = starting sector to r/w
  1457.     moveq    #0,d2            ; clear d2
  1458.     move.w    xcount(a6),d2        ; d2.l = # sectors to r/w
  1459.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1460.     bne.s    ahrwb            ; if so, go on
  1461.                     ; else log -> phys sector mapping
  1462.     mulu    sizr,d1            ; d1.l = phys start sector to r/w
  1463.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1464.  
  1465. ahrwb:    move.l    xbuf(a6),a1        ; a1.l = buffer addr to r/w
  1466.     cmpi.l    #MAXSECTORS,d2        ; more than one DMAfull?
  1467.     bhi.s    ahrwc            ; if not, do only one DMAfull
  1468.     move.w    d2,xcount(a6)        ; else xcount(a6) = # sects requested
  1469.     bra.s    ahrw2
  1470. ahrwc:    move.w    #MAXSECTORS,xcount(a6)    ; xcount(a6) = 1 DMAfull of sects
  1471. ahrw2:    btst    #0,xbuf+3(a6)        ; an odd boundary?
  1472.     beq.s    ahrw4            ; no, so do normally
  1473.  
  1474.     cmpi.w    #2,xcount(a6)        ; can only do 2 at a time tops this way
  1475.     bls.s    ahrw3
  1476.     move.w    #2,xcount(a6)
  1477.  
  1478. ahrw3:    move.l    _dskbufp,a1        ; use the bios buffer for this transfer
  1479.  
  1480.     btst    #0,xrw+1(a6)        ; is this a write?
  1481.     beq.s    ahrw4            ; no, so go fill buffer from disk
  1482.  
  1483.     move.l    a1,-(sp)        ; preserve a1 = dest
  1484.     movea.l    xbuf(a6),a2        ; a2.l = source
  1485.     move.w    xcount(a6),-(sp)    ; # sectors to be moved
  1486.     bsr    smove            ; move sectors from a2 to a1
  1487.     addq.l    #2,sp            ; clean up stack
  1488.     movea.l    (sp)+,a1        ; restore a1 = dest buffer address
  1489.  
  1490. ahrw4:    movem.l    d1-d2,-(sp)        ; save total count and start sector
  1491.     move.w    xdev(a6),-(sp)
  1492.     move.l    d1,-(sp)
  1493.     move.w    xcount(a6),-(sp)    ; count
  1494.     move.l    a1,-(sp)        ; buffer
  1495.     move.w    xrw(a6),-(sp)
  1496.     bsr    _do_rw
  1497.     adda    #14,sp
  1498.     movem.l    (sp)+,d1-d2        ; restore total count and start sector
  1499.     tst.l    d0            ; any errors there?
  1500.     beq.s    ahrw8            ; no, go on normally
  1501.  
  1502.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1503.     bne    ahrw7            ; if not, give up
  1504.     st    mcrw            ; else it's mc returned when r/w
  1505.     bra    mcchg            ; and go check if media has changed
  1506.  
  1507. ahrw8:    btst    #0,xbuf+3(a6)        ; on odd boundary?
  1508.     beq.s    ahrw5            ; if not, go on normally
  1509.     btst    #0,xrw+1(a6)        ; was it a read?
  1510.     bne.s    ahrw5            ; if it wasn't, go on normally
  1511.                     ; else
  1512.     movea.l    xbuf(a6),a1        ; must move data read to desired dest
  1513.     movea.l    _dskbufp,a2        ; from dskbuf
  1514.     move.w    xcount(a6),-(sp)    ; # of sectors to move
  1515.     bsr    smove
  1516.     addq.l    #2,sp            ; clean up stack
  1517.  
  1518. ahrw5:    moveq    #0,d0            ; clear d0
  1519.     move.w    xcount(a6),d0        ; #sectors we did
  1520.     sub.l    d0,d2            ; #sectors left to do
  1521.     add.l    d0,d1            ; next starting sector to r/w
  1522.     asl.l    #8,d0            ; d0 = #bytes we did
  1523.     add.l    d0,d0            ;    = #sectors * 512
  1524.     add.l    d0,xbuf(a6)        ; buf += (sectors_done * sector size)
  1525.     tst.l    d2            ; anything left to r/w?
  1526.     bne    ahrwb            ; if so, continue
  1527.                     ; check if wrote to boot sector
  1528. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1529.     btst    #0,d0            ; was it a write?
  1530.     beq    ahrw6            ; if not, done
  1531.     btst    #3,d0            ; was it a physical operation?
  1532.     bne    ahrw6            ; if it was, done
  1533.     btst    #1,d0            ; ignore media change?
  1534.     bne.s    wrfat            ; if so, update FAT chksums if appl.
  1535.     tst.l    strec            ; wrote to boot sector?
  1536.     bne.s    wrfat            ; if not, update FAT chksums if appl.
  1537.     lea    mcflgs,a0        ; else, a0 = ptr to mcflgs table
  1538.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1539.     move.b    #2,(a0)            ; assume medium has changed
  1540.  
  1541. wrfat:    moveq    #0,d0            ; clear d0
  1542.     move.b    cpun+1,d0        ; d0.b = pun of dev
  1543.     btst.b    d0,rmbits        ; is drive removable?
  1544.     beq    ahrw6            ; if not, done
  1545.                     ; else check if wrote to FATs
  1546.     lea    fatend,a0        ; a0 = ptr to fatend table
  1547.     move.w    xdev(a6),d0        ; d0 = device number
  1548.     add.w    d0,d0            ; d0*2 = index into table of words
  1549.     moveq    #0,d1            ; coerce to long
  1550.     move.w    (a0,d0.w),d1        ; d1 = last FAT's ending sector
  1551.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1552.     blt    ahrw6            ; if so, done
  1553.  
  1554.     lea    fatst,a0        ; a0 = ptr to fatst table
  1555.     moveq    #0,d2            ; coerce to long
  1556.     move.w    (a0,d0.w),d2        ; d2 = last FAT's starting sector
  1557.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1558.     bgt    ahrw6            ; if so, done
  1559.                     ; else update FAT sector checksums
  1560.     move.l    stbuf,a0        ; a0 = ptr to buffer w/ written data
  1561.     lea    fatsum,a1        ; a1 = ptr to start of fatsum table
  1562.     move.w    xdev(a6),d0        ; d0 = dev number
  1563.     mulu.w    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1564.     adda.l    d0,a1            ; a1 = ptr to dev's first FAT chksum
  1565.     move.l    strec,d0        ; d0 = first sector wrote to
  1566.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1567.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1568.                     ;     no adjustments needed
  1569.      blt.s    wrfat1            ; if strec < start(last FAT)
  1570.                     ;     begin from start(last FAT)
  1571.     move.l    strec,d2        ; else begin from strec
  1572.     adda.l    d0,a1            ; a1 = ptr to fatsum to be updated
  1573.     bra.s    wrfat2
  1574.  
  1575. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1576.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1577.     add.l    d0,d0
  1578.     adda.l    d0,a0            ; a0 = pt to addr of buf for update
  1579.  
  1580. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1581.     ble.s    wrfat3            ;     stop at end(last FAT)
  1582.     move.l    endrec,d1        ; else stop at endrec
  1583.  
  1584. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1585. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1586.     subq.w    #1,d2            ; dbra likes one less
  1587.     clr.l    temp            ; initialize sum
  1588. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1589.     adda.l    #512,a0            ; point to next 512 bytes
  1590.     dbra    d2,wrfat5        ; until one logical sector is done
  1591.     bsr    csum            ; obtain checksum
  1592.     move.b    d0,(a1)+        ; record new fat checksum
  1593.     dbra    d1,wrfat4        ; do until all are updated
  1594.  
  1595. ahrw6:    clr.l    d0            ; got here with no errors!
  1596.     bra.s    ahrw7
  1597.  
  1598. ismc:    tst.b    mcrw            ; media change returned by r/w?
  1599.     beq    onemc            ; no, only dev has changed
  1600.     move.b    #2,d0            ; d0.b = value to set to
  1601.     move.w    xdev(a6),d1        ; d1.w = dev number
  1602.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1603.     bsr    s_mc_xst        ; set mcflgs and xst flags for devs
  1604.     bra.s    retmc            ; return media change detected
  1605.  
  1606. onemc:    lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1607.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1608.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1609.     lea    xst,a0            ; a0 = ptr to drive existence table
  1610.     adda.w    xdev(a6),a0        ; a0 = ptr to xst flag of dev
  1611.     move.b    #2,(a0)            ; assume dev exists
  1612.  
  1613. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1614. ahrw7:    unlk    a6
  1615.     bra    ret2calr        ; return to caller
  1616.  
  1617.  
  1618. ;----------------
  1619. ;
  1620. ;  Copy unaligned sectors
  1621. ;  (this is *supposed* to be slow!)
  1622. ;
  1623. ;    Passed:    4(sp).w    = # of sectors (known to be 1 or 2)
  1624. ;        a2    -> source sector
  1625. ;        a1    -> dest buffer (oddly aligned)
  1626. ;
  1627. smove:    move.w    4(sp),d0        ; d0 = # 512-byte sectors to move
  1628.     asl.w    #8,d0            ; d0 * 512 = # bytes to move
  1629.     add.w    d0,d0
  1630.     subq.w    #1,d0            ; dbra likes one less
  1631. smove1:    move.b    (a2)+,(a1)+
  1632.     dbra    d0,smove1
  1633.     rts
  1634.  
  1635.  
  1636. ;
  1637. ;+
  1638. ; _do_rw - called to read/write no more than 128K to an even boundary
  1639. ;
  1640. ; Passed:    dev    $10(sp).W
  1641. ;        recno    $c(sp).L
  1642. ;        count    $a(sp).W
  1643. ;        buf    6(sp).L
  1644. ;        rw    4(sp).W        ; non-zero -> write
  1645. ;
  1646. ;-
  1647. _do_rw:
  1648.     move.w    d3,-(sp)        ; preserve d3
  1649.  
  1650. sasrw0:    move.w    _retries,retrycnt    ; setup retry counter
  1651.  
  1652.     move.w    6(sp),d3        ; rw
  1653.     btst    #2,d3            ; are retries disabled?
  1654.     beq.s    sasrw1            ; no, act normally
  1655.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1656.  
  1657. sasrw1:    lea    2(sp),a1        ; frame pointer
  1658.     move.l    $c(a1),d0        ; sect.L
  1659.     move.w    4(a1),d3        ; rw
  1660.  
  1661.     btst    #3,d3            ; physical unit operation
  1662.     beq.s    sasrw2            ; no, so do log->phys mapping
  1663.  
  1664.     move    $10(a1),cpun        ; get unit number
  1665.     bra.s    sasrw3            ; and use that as the physical unit
  1666.  
  1667. sasrw2:    clr    d2            ; coerce byte to word
  1668.     move.w    $10(a1),d1        ; get device
  1669.      lea    pun,a2
  1670.     move.b    (a2,d1.w),cpun+1    ; get physical unit number
  1671. sasrw3:    move.w    cpun,-(sp)        ; dev
  1672.     move.l    6(a1),-(sp)        ; buf
  1673.     move.w    $a(a1),-(sp)        ; count
  1674.  
  1675.     btst    #3,d3            ; physical operation?
  1676.     bne.s    sasrw4            ; yes, so no offset
  1677.  
  1678.     add.w    d1,d1            ; d1*2*2 = index into table of longs
  1679.     add.w    d1,d1
  1680.     lea    start,a2
  1681.     add.l    (a2,d1.w),d0        ; adjust sector number
  1682.  
  1683. sasrw4:    move.l    d0,-(sp)        ; sect
  1684.     btst    #0,d3            ; read or write?
  1685.     bne.s    sasrw5            ; (write)
  1686.     bsr    _hread            ; read sectors
  1687.     bra.s    sasrw6
  1688. sasrw5:    bsr    _hwrite            ; write sectors
  1689. sasrw6:    adda    #12,sp            ; (cleanup stack)
  1690.     tst.l    d0            ; errors?
  1691.     beq    sasrwr            ; no -- success
  1692.  
  1693.     bsr    errcode            ; find error code
  1694.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  1695.     beq.s    sasrw7
  1696.     cmpi.b    #WRTPRTD,d0        ; write on write-protected media?
  1697.     beq.s    sasrw9
  1698.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  1699.     beq.s    sasrwe
  1700.  
  1701.     subq.w    #1,retrycnt        ; drop retry count and retry
  1702.     bpl    sasrw1
  1703.  
  1704.     move    6(sp),d1        ; get r/w and flags word
  1705.     move.l    #EREADF,d0        ; read error code
  1706.     btst    #0,d1            ; is it a write?
  1707.     beq.s    sasrwa
  1708.     move.l    #EWRITF,d0        ; write error code
  1709.     bra.s    sasrwa
  1710.  
  1711. sasrw7:    move.w    6(sp),d1        ; get r/w and flags word
  1712.     andi.b    #$a,d1            ; no media change/physical operation?
  1713.     beq.s    sasrw8            ; if not, return media change
  1714.     move.b    #1,d0            ; d0.b = medium may have changed
  1715.     move.w    $12(a6),d1        ; d1.w = dev number
  1716.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1717.     bsr    s_mc_xst        ; set mcflgs and xst flags for dev
  1718.     bra    sasrw0            ; start all over
  1719.     
  1720. sasrw8:    move.l    #E_CHNG,d0        ; media change detected
  1721.     bra.s    sasrwr            ; return
  1722.  
  1723. sasrw9:    move.l    #EWRPRO,d0        ; write on write-protected media
  1724.     bra.s    sasrwf
  1725.  
  1726. sasrwe:    move.l    #EDRVNR,d0        ; drive not ready
  1727. sasrwf:    move.w    6(sp),d1        ; get r/w and flags word
  1728.  
  1729. sasrwa:    btst    #3,d1            ; is this a physical operation?
  1730.     beq.s    sasrwc            ; no, call critical error handler
  1731.                     ; else find 1st drive of current unit
  1732.     lea    pun,a0            ; a0 = ptr to pun table
  1733.     move.w    cpun,d2            ; d1 = current pun
  1734.     moveq    #0,d1            ; d2 = index into pun table
  1735. sasrwb:    cmp.b    (a0,d1.w),d2        ; 1st drive of unit?
  1736.     beq.s    sasrwd            ; if so, get drive number 
  1737.     addq.w    #1,d1            ; else, get next drive number
  1738.     cmpi.w    #MAXUNITS,d1        ; reach end of pun table?
  1739.     bge.s    sasrwr            ; if so, forget it
  1740.     bra.s    sasrwb            ; else try this next drive
  1741.  
  1742. sasrwc:    move.w    $12(sp),d1        ; d1 = drive number
  1743. sasrwd:    bsr    critic
  1744.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1745.     beq    sasrw0            ; if yes, go retry
  1746.  
  1747. sasrwr:    move.w    (sp)+,d3        ; remember to restore d3
  1748.     rts
  1749.  
  1750.  
  1751. ;
  1752. ;----------------
  1753. ;
  1754. ; Check for media change on hard disk
  1755. ; Synopsis:    _sasi_mediach(dev)
  1756. ;        WORD dev;        4(sp).w
  1757. ;
  1758. ; Returns:    0L - media definitely has not changed
  1759. ;        1L - media _may_ have changed
  1760. ;        2L - media definitely has changed
  1761. ;
  1762. ; Uses:        d0, d1, a0, a1
  1763. ;
  1764. ; Comments:
  1765. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1766. ;            If _sasi_mediach() was called less than 1 s
  1767. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1768. ;            not changed then, assume medium still has not 
  1769. ;            changed.
  1770. ;
  1771. _sasi_mediach:
  1772.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1773.     move.w    4(sp),d1        ; d1 = current drive
  1774.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1775.     moveq    #0,d0            ; d0 = mcflg for current drive
  1776.     move.b    (a0,d1.w),d0    
  1777.     tst.b    d0            ; has medium changed?
  1778.     bne.s    decided            ; if yes or maybe, return result
  1779.                     ; else verify that it has not
  1780.     move.l    lastmdctm,d2        ; time media change was last called
  1781.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1782.     bcc.s    decided            ;    assume medium not changed
  1783.  
  1784.     lea    pun,a1            ; ptr to beginning of pun table
  1785.     clr.w    d2            ; coerce byte to word
  1786.     move.b    (a1,d1.w),d2        ; d2 = pun current drive belongs to
  1787.  
  1788.     btst.b    d2,rmbits        ; is pun removable?
  1789.     beq.s    notchngd        ; if not, medium has not changed
  1790.  
  1791.     movem.w    d1-d2,-(sp)        ; else save registers
  1792.     move.w    d2,-(sp)        ; physical unit number
  1793.     bsr    testunit        ; verify by doing test unit ready
  1794.     addq.l    #2,sp
  1795.     movem.w    (sp)+,d1-d2        ; restore registers
  1796.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  1797.     addi.l    #200,lastmdctm        ; 
  1798.     tst.w    d0            ; return good status?
  1799.     beq.s    notchngd        ; if yes, return medium not changed
  1800.     moveq    #1,d0            ; else return medium may have changed
  1801.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  1802.     bra.s    decided
  1803. notchngd:
  1804.     moveq    #0,d0            ; return medium has not changed
  1805. decided:
  1806.     bra    ret2calr        ; return to caller
  1807.  
  1808.  
  1809. ;+
  1810. ; s_mc_xst - set mcflgs and drive existence flags 
  1811. ;         for drives belonging to a physical unit 
  1812. ;         to value passed
  1813. ;
  1814. ; Passed:    d0.b - value to set to
  1815. ;         d1.w - dev number
  1816. ;        d2.b - physical unit #
  1817. ;-
  1818. s_mc_xst:
  1819.     movem.l    a0-a2,-(sp)    ; save registers
  1820.     move.w    d1,-(sp)    ; save dev number
  1821.     lea    mcflgs,a0    ; a0 = ptr to mcflgs table
  1822.     lea    pun,a1        ; a1 = ptr to pun table
  1823.     lea    xst,a2        ; a2 = ptr to drive existence table
  1824. back:    cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1825.     bne.s    oppdir        ; if not, try opposition direction
  1826.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1827.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1828.     dbra    d1,back        ; try next one in backward direction
  1829. oppdir:    move.w    (sp)+,d1    ; get device number again
  1830. forth:    addq.w    #1,d1        ; try next one in forward direction
  1831.     cmp.w    #MAXUNITS,d1    ; all units checked?
  1832.     bge.s    setr        ; if yes, get ready to return
  1833.     cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1834.     bne.s    setr        ; if not, get ready to return
  1835.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1836.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1837.     bra.s    forth        ; continue to search
  1838. setr:    movem.l    (sp)+,a0-a2    ; restore registers
  1839.     rts
  1840.  
  1841.  
  1842. ;
  1843. ;--------------------- Low-Level Driver -------------------
  1844.  
  1845. ;----------------
  1846. ;
  1847. ;  Hardware definitions
  1848. ;
  1849. wdc        equ    $ffff8604
  1850. wdl        equ    $ffff8606
  1851. wdcwdl        equ    wdc        ; used for long writes
  1852. xwdl        equ    wdl-wdc        ; offset from wdc to wdl
  1853.  
  1854. dmahi        equ    $ffff8609
  1855. dmamid        equ    dmahi+2
  1856. dmalow        equ    dmamid+2
  1857. gpip        equ    $fffffa01
  1858.  
  1859.  
  1860. ;----------------
  1861. ;
  1862. ;  Tunable (delay) values (in number of _hz_200 ticks) for ACSI
  1863. ;
  1864. ltmout        equ    600        ; long-timeout (3 S)
  1865. stmout        equ    20        ; short-timeout (100 mS)
  1866. slwstmout    equ    40        ; short-timeout (200 mS) for slow ACSI
  1867. slwltmout    equ    4000        ; long-timeout (20 S) for slow ACSI
  1868.  
  1869.  
  1870. ;----------------
  1871. ;
  1872. ; LONG _qdone() - Wait for command byte handshake
  1873. ; LONG _fdone() - Wait for operation complete
  1874. ; Passed:    nothing
  1875. ;
  1876. ; Returns:    EQ: no timeout
  1877. ;        MI: timeout condition
  1878. ;
  1879. ; Uses:        D0
  1880. ;
  1881. ;
  1882. ;-
  1883. _slwfdone:                ; fdone for slow ACSI devices
  1884.     move.l    #slwltmout,d0        ; wait 200 milliseconds
  1885.     bra.s    qd1
  1886.  
  1887. _fdone:    move.l    #ltmout,d0
  1888.     bra.s    qd1
  1889.  
  1890. _slwqdone:                ; qdone for slow ACSI devices
  1891.     moveq    #slwstmout,d0        ; wait 200 milliseconds
  1892.     bra.s    qd1
  1893.  
  1894. _qdone:    moveq    #stmout,d0
  1895.  
  1896. qd1:    add.l    _hz_200,d0
  1897. qd2:    cmp.l    _hz_200,d0        ; timeout?
  1898.     bcs.s    qdq            ; (i give up, return NE)
  1899.     btst    #5,gpip            ; interrupt?
  1900.     bne.s    qd2            ; (not yet)
  1901.  
  1902.     moveq    #0,d0            ; return EQ (no timeout)
  1903.     rts
  1904.  
  1905. qdq:    moveq    #-1,d0
  1906.     rts
  1907.  
  1908.  
  1909. ;----------------
  1910. ;
  1911. ; Wait for end of SASI command
  1912. ;
  1913. ; Passed:    d0 value to be written to wdl
  1914. ;
  1915. ; Returns:    EQ: success (error code in D0.W)
  1916. ;        MI: timeout (-1 in D0.W)
  1917. ;        NE: failure (SASI error code in D0.W)
  1918. ;
  1919. ; Uses:        d0,d1
  1920. ;-
  1921. _slwendcmd:
  1922.     move    d0,d1            ; preserve wdl value
  1923.     bsr    _slwfdone        ; wait for operation complete
  1924.     bra.s    end1
  1925.  
  1926. _endcmd:
  1927.     move    d0,d1            ; preserve wdl value
  1928.     bsr    _fdone            ; wait for operation complete
  1929.  
  1930. end1:    bmi.s    endce            ; (timed-out, so complain)
  1931.  
  1932.     move.w    d1,wdl
  1933.     move.w    wdc,d0            ; get the result
  1934.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  1935.                     ; do a ReadSense command to learn more
  1936. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  1937.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  1938.     rts                
  1939.  
  1940.  
  1941. ;+
  1942. ;  Handle command timeout;
  1943. ;  Unlock DMA chip and return completion status;
  1944. ;-
  1945. _hto:    moveq    #-1,d0        ; indicate timeout
  1946. _hdone:    move.w    #$80,wdl    ; Landon's code seems to presume we
  1947.     tst.w    wdc
  1948.     sf    flock        ; NOW, signal that we are done
  1949.     rts
  1950.  
  1951.  
  1952. ;+
  1953. ; delay()
  1954. ;    5 - 10ms kludge delay for message byte sent back by controller.
  1955. ;-
  1956. _delay:    move.l    lastacstm,d0        ; d0 = controller last accessed time
  1957. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  1958.     bcc.s    wait            ;    wait()
  1959.     rts
  1960.  
  1961.  
  1962. ;
  1963. ;-----------------
  1964. ;
  1965. ; _hread(sectno, count, buf, dev)
  1966. ; LONG sectno;         4(sp)
  1967. ; WORD count;         8(sp)
  1968. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1969. ; WORD dev;        $e(sp)
  1970. ;
  1971. ; Returns:    -1 on timeout
  1972. ;        0 on success
  1973. ;        nonzero on error
  1974. ;
  1975. ;-
  1976. _hread:    bsr    _delay
  1977.     movea.l    #wdc,a0            ; pointer to DMA chip
  1978.     st    flock            ; lock FIFO
  1979.  
  1980.     move    #$88,xwdl(a0)    ;wdl
  1981.     clr.l    d0
  1982.     move.w    $0e(sp),d0        ; get unit number
  1983.     lsl.w    #5,d0
  1984.     swap    d0
  1985.     ori.l    #$0008008a,d0        ; 08 wdc, 8a wdl
  1986.     move.l    d0,(a0)     ;wdcwdl
  1987.  
  1988.     move.l    $a(sp),-(sp)        ; set DMA address
  1989.     bsr    _setdma
  1990.     addq.l    #4,sp
  1991.  
  1992.     bsr    _setss            ; set sector and size
  1993.     bmi    _hto
  1994.  
  1995.     move.w    #$190,xwdl(a0)    ;wdl
  1996.     move.w    #$90,xwdl(a0)    ;wdl
  1997.     move.w    8(sp),(a0)     ;wdc    ; write sector count to DMA chip
  1998.     move.w    #$8a,xwdl(a0)    ;wdl
  1999.     move.l    #$00000000,(a0) ;wdcwdl    ; control byte  0 wdc 0 wdl
  2000.  
  2001.     move.w    #$8a,d0
  2002.     bsr    _endcmd
  2003.  
  2004. hrx:    bra    _hdone            ; cleanup after IRQ
  2005.  
  2006.  
  2007. ;
  2008. ;----------------
  2009. ;
  2010. ; _hwrite(sectno, count, buf, dev)
  2011. ; LONG sectno;         4(sp)
  2012. ; WORD count;         8(sp)
  2013. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  2014. ; WORD dev;        $e(sp)
  2015. ;
  2016. ;-
  2017. _hwrite:
  2018.     bsr    _delay
  2019.     movea.l    #wdc,a0            ; pointer to DMA chip
  2020.     st    flock            ; lock FIFO
  2021.  
  2022.     move.l    $a(sp),-(sp)        ; set DMA address
  2023.     bsr    _setdma
  2024.     addq.l    #4,sp
  2025.  
  2026.     move.w    #$88,xwdl(a0)    ;wdl
  2027.     clr.l    d0
  2028.     move.w    $0e(sp),d0        ; get unit number
  2029.     lsl.w    #5,d0
  2030.     swap    d0
  2031.     ori.l    #$000a008a,d0        ; 0a wdc 8a wdl
  2032.     move.l    d0,(a0)     ;wdcwdl
  2033.  
  2034.     bsr    _setss
  2035.     bmi    _hto
  2036.  
  2037.     move.w    #$90,xwdl(a0)    ;wdl
  2038.     move.w    #$190,xwdl(a0)    ;wdl
  2039.     move.w    8(sp),(a0)     ;wdc    ; sector count for DMA chip's benefit
  2040.     move.w    #$18a,xwdl(a0)
  2041.     move.l    #$00000100,(a0) ;wdcwdl
  2042.  
  2043.     move.w    #$18a,d0
  2044.     bsr    _endcmd
  2045.  
  2046. hwx:    bra    _hdone            ; cleanup after IRQ
  2047.  
  2048.  
  2049. ;
  2050. ;----------------
  2051. ;
  2052. ; Set DMA address
  2053. ;
  2054. ; void _setdma(addr)
  2055. ; LONG addr;
  2056. ;-
  2057. _setdma:
  2058.     move.b    7(sp),dmalow
  2059.     move.b    6(sp),dmamid
  2060.     move.b    5(sp),dmahi
  2061.     rts
  2062.  
  2063.  
  2064. ;----------------
  2065. ;
  2066. ; Set sector number and number of sectors
  2067. ;
  2068. _setss:    move.w    #$8a,xwdl(a0)
  2069.  
  2070.     bsr    _qdone            ; wait for controller to take command
  2071.     bmi    setsse
  2072.  
  2073.     move.b    9(sp),d0        ; construct sector#
  2074.     swap    d0
  2075.     move.w    #$008a,d0
  2076.     move.l    d0,(a0)     ;wdcwdl    ; write MSB sector# + devno
  2077.     bsr    _qdone
  2078.     bmi    setsse
  2079.  
  2080.     move.b    10(sp),d0        ; write MidSB sector#
  2081.     swap    d0
  2082.     move.w    #$008a,d0
  2083.     move.l    d0,(a0)     ;wdcwdl
  2084.     bsr    _qdone
  2085.     bmi    setsse
  2086.  
  2087.     move.b    11(sp),d0        ; write LSB sector#
  2088.     swap    d0
  2089.     move.w    #$008a,d0
  2090.     move.l    d0,(a0)     ;wdcwdl
  2091.     bsr    _qdone
  2092.     bmi    setsse
  2093.  
  2094.     move.w    12(sp),d0        ; write sector count
  2095.     swap    d0
  2096.     move.w    #$008a,d0
  2097.     move.l    d0,(a0)     ;wdcwdl
  2098.     bsr    _qdone
  2099.  
  2100. setsse:    rts
  2101.  
  2102.  
  2103. ;
  2104. ;----------------
  2105. ;
  2106. ;  _inquiry - get device-specific parameters
  2107. ;
  2108. ;    Synopsis:    LONG _inquiry(physunit#, parms)
  2109. ;        WORD physunit#;            4(sp).W
  2110. ;        char *parms;            6(sp).L
  2111. ;
  2112. ; Old driver uses these two lines which do NOT do 
  2113. ; "d0 = (dev << 5) << 16" because the hi word of
  2114. ; D0 before the swap (lo word after) is garbage.
  2115. ;    lsl.b    #5,d0
  2116. ;    swap    d0
  2117. ;-
  2118. _inquiry:
  2119.     bsr    _delay
  2120.     st    flock            ; lock FIFO
  2121.     move.l    6(sp),-(sp)        ; -> parameter block address
  2122.     bsr    _setdma            ; set DMA there
  2123.     addq.l    #4,sp
  2124.     movea.l    #wdc,a0            ; pointer to DMA chip
  2125. ; write command and phyunit#
  2126.     move.w    #$88,xwdl(a0)    ;wdl
  2127.     move.w    4(sp),d0        ; d0 = (physunit# << 5) << 16
  2128.     moveq    #21,d1
  2129.     lsl.l    d1,d0            
  2130.     or.l    #$0012008a,d0        ; write physunit# + Inquiry + FIFO bits
  2131.     move.l    d0,(a0)        ;wdcwdl    ; inquiry+physunit# wdc 8a wdl (byte 0)
  2132.     bsr    _qdone
  2133.     bmi    inq
  2134.  
  2135.     move.l    #$8a,d1            ; d1 = byte to be sent
  2136.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2137.     bsr    _qdone
  2138.     bmi    inq
  2139.  
  2140.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2141.     bsr    _qdone
  2142.     bmi    inq
  2143.  
  2144.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2145.     bsr    _qdone
  2146.     bmi    inq
  2147.  
  2148.     move.l    #$0010008a,(a0)    ;wdcwdl    ; 16 byte of parameters (byte 4)
  2149.     bsr    _qdone
  2150.     bmi    inq
  2151.  
  2152.     move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2153.     move.w    #$90,xwdl(a0)    ;wdl
  2154.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2155.     move.w    #$8a,xwdl(a0)    ;wdl
  2156.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2157.     move.w    #$8a,d0            ; wdl value
  2158.     bsr    _endcmd            ; wait for command completion
  2159. inq:    bra    _hdone
  2160.  
  2161.  
  2162. ;
  2163. ;---------------
  2164. ;
  2165. ;  LONG _rq_sense() - get non-extended sense data from target
  2166. ;  LONG _rq_xsense() - get extended sense data from target
  2167. ;
  2168. ;  Passed:
  2169. ;    WORD physunit#;            4(sp).W        $6(sp).w
  2170. ;    char data[];            6(sp).L        $8(sp).l
  2171. ;
  2172. ;  Returns:
  2173. ;        0 : OK
  2174. ;    non-0 : ERROR
  2175. ;
  2176. _rq_sense:
  2177.     moveq    #3,d2            ; do it 4 times
  2178.     move.w    #0,-(sp)        ; request 4 bytes of sense data
  2179.     bra.s    rq0
  2180. _rq_xsense:
  2181.     moveq    #0,d2            ; do it one time
  2182.     move.w    #16,-(sp)        ; request 16 bytes of sense data
  2183. rq0:    bsr    _delay            ; kludge delay
  2184.     movea.l    #wdc,a0
  2185.     st    flock            ; lock FIFO
  2186.     move.l    8(sp),-(sp)        ; -> sense data buffer address
  2187.     bsr    _setdma            ; set DMA there
  2188.     addq.l    #4,sp
  2189.  
  2190.      move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2191.     move.w    #$90,xwdl(a0)    ;wdl
  2192.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2193.  
  2194.     moveq    #0,d0
  2195. rq1:    move.w    #$88,xwdl(a0)    ;wdl
  2196.     move.w    6(sp),d0        ; d0 = (dev << 5) << 16
  2197.     lsl.b    #5,d0
  2198.     swap    d0            ; in upper word
  2199.     or.l    #$0003008a,d0        ; write dev#+Request Sense+FIFO bits
  2200.     move.l    d0,(a0)        ;wdcwdl    ; rqsense+dev wdc 8a wdl (byte 0)
  2201.     bsr    _qdone
  2202.     bmi.s    wdq1
  2203.  
  2204.     move.l    #$8a,d1        ; byte to be sent
  2205.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2206.     bsr    _qdone
  2207.     bmi.s    wdq1
  2208.  
  2209.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2210.     bsr    _qdone
  2211.     bmi.s    wdq1
  2212.  
  2213.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2214.     bsr    _qdone
  2215.     bmi.s    wdq1
  2216.  
  2217.     move.w    (sp),d0            ; # bytes of sense data requested
  2218.     swap    d0
  2219.     or.l    d1,d0
  2220.     move.l    d0,(a0)        ;wdcwdl    ; byte 4
  2221.     bsr    _qdone
  2222.     bmi.s    wdq1
  2223.  
  2224.     move.w    #$8a,xwdl(a0)    ;wdl
  2225.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2226.     move.w    #$8a,d0            ; wdl value
  2227.     bsr    _endcmd            ; wait for command completion
  2228.     tst.w    d0
  2229.     bmi.s    wdq1
  2230.     dbra    d2,rq1            ; go back until done
  2231. wdq1:    addq.l    #2,sp            ; clean up stack
  2232.     bra    _hdone
  2233.  
  2234.  
  2235. ;
  2236. ;----------------
  2237. ;
  2238. ;  testunit - Test Unit Ready
  2239. ;
  2240. ;    Synopsis:    LONG testunit(dev)
  2241. ;        WORD dev;        4(sp).W
  2242. ;
  2243. ;    Uses:  d0, d1, and a0
  2244. ;-
  2245. tst:    dc.b    0    ; test unit ready command + devno (upper 3 bits)
  2246.     dc.b    0    ; (unused)
  2247.     dc.b    0    ; (unused)
  2248.     dc.b    0    ; (unused)
  2249.     dc.b    0    ; (unused)
  2250.     dc.b    0    ; (unused)
  2251. .even
  2252.  
  2253. testunit:
  2254.     bsr    _delay
  2255.     move.w    4(sp),d0        ; set dev#
  2256.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2257.     lea    tst,a0            ; pick up pointer to the command block
  2258.     or.b    d0,(a0)            ; stuff into command frame
  2259.     clr.w    d0
  2260.     st    flock            ; lock FIFO
  2261.     move.w    #$88,wdl
  2262.     move.b    (a0)+,d0        ; get the command byte
  2263.     swap    d0
  2264.     move.w    #$8a,d0
  2265.     move.l    d0,wdcwdl        ; byte wdc 8a wdl
  2266.  
  2267.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2268. tst1:    bsr    _qdone
  2269.     bmi    _hto
  2270.     move.b    (a0)+,d0        ; next byte of command
  2271.     swap    d0
  2272.     move.w    #$8a,d0
  2273.     move.l    d0,wdcwdl
  2274.     dbra    d1,tst1
  2275.     bsr    _endcmd            ; wait for command completion
  2276.     bra    _hdone            ; cleanup after IRQ
  2277.  
  2278.  
  2279. ;
  2280. ;----------------
  2281. ;
  2282. ;  stunit - Start/Stop unit
  2283. ;
  2284. ;    Synopsis:    LONG stunit(dev, flag)
  2285. ;        WORD dev;        4(sp).W
  2286. ;        WORD flag;        6(sp).W
  2287. ;
  2288. ;    Uses:  d0, d1, and a0
  2289. ;-
  2290. stcmd:    dc.b    $1b    ; start/stop command + devno (upper 3 bits)
  2291.     dc.b    0    ; (unused)
  2292.     dc.b    0    ; (unused)
  2293.     dc.b    0    ; (unused)
  2294.     dc.b    0    ; bit 0 = to flag start or stop unit
  2295.     dc.b    0    ; (unused)
  2296. .even
  2297.  
  2298. _stunit:
  2299.     bsr    _delay
  2300.     move.w    4(sp),d0        ; set dev#
  2301.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2302.     lea    stcmd,a0        ; pick up pointer to the command block
  2303.     or.b    d0,(a0)            ; stuff dev # into command frame
  2304.     move.b    7(sp),4(a0)        ; stuff flag into command frame
  2305.     moveq    #0,d0            ; clear d0
  2306.     st    flock            ; lock FIFO
  2307.     move.w    #$88,wdl
  2308.     move.b    (a0)+,d0        ; get the command byte
  2309.     swap    d0
  2310.     move.w    #$8a,d0
  2311.     move.l    d0,wdcwdl        ; byte wdc 8a wdl
  2312.     
  2313.     moveq    #(5-1),d1        ; write next 5 bytes of command
  2314. st1:    bsr    _slwqdone
  2315.     bmi    _hto
  2316.     move.b    (a0)+,d0        ; next byte of command
  2317.     swap    d0
  2318.     move.w    #$8a,d0
  2319.     move.l    d0,wdcwdl        ; byte wdc 8a wdl
  2320.     dbra    d1,st1
  2321.     bsr    _slwendcmd        ; wait for command completion
  2322.     moveq    #2,d1            ; /* ~ 5 millisecond delay */
  2323.     add.l    _hz_200,d1        ; /* for slow acsi devices */
  2324. .0:    cmp.l    _hz_200,d1        ;
  2325.     bcc.s    .0            ;
  2326.     bra    _hdone            ; cleanup after IRQ
  2327.  
  2328.  
  2329. ;
  2330. ;---------------- Resident Installer -------------------
  2331.  
  2332. isasi5:    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  2333.     move.l    acsi0idle,idlelmt    ; init idle time limit for ACSI 0
  2334.     move.b    #$ff,idlelmt        ; set high byte to show this driver
  2335.                     ;  handles spinning down of ACSI 0
  2336.  
  2337.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  2338.     bls.s    nboot0        ; if not, don't need to replace GEMDOS buffers
  2339.                 ; else check if there is enough memory for
  2340. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  2341.     tst.l    d0        ; enough?
  2342.     bpl.s    okbig        ; if so, build the list
  2343.     move.w    minbigsect,d0    ; d0 = minimum big sector
  2344.     cmp.w    maxssz,d0    ; is minimum big sector >= maxssz?
  2345.     bcc.s    regsect        ; if so, give up
  2346.     move.w    d0,maxssz    ; else try minimum big sector
  2347.     bra.s    chkmem
  2348. regsect:
  2349.     move.w    #512,maxssz    ; else, cannot handle big sectors
  2350.     bra.s    nboot0
  2351.  
  2352. okbig:    move.l    d1,tokeep    ; update amout of memory to be kept
  2353.     lea    i_sasi1,a0    ; a0 = ptr to beginning of new buffer lists
  2354.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  2355.     bsr    list_init    ; initialize the buffer list
  2356.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  2357.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  2358.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  2359.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  2360.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  2361.  
  2362. nboot0:    bsr    pool_install    ; attempt to install more OS pool
  2363.     add.l    tokeep,d0    ; compute value for Ptermres() or Mshrink
  2364.     tst.w    bootloaded    ; exit to GEMDOS?
  2365.     beq    nboot2        ; (yes -- not boot loaded)
  2366.  
  2367. ;+
  2368. ;  Return to TOS ROMs
  2369. ;    - set default boot device to C:
  2370. ;    - Print silly message
  2371. ;    - Mshrink() memory that was alloc'd to us
  2372. ;    - set magic# in D7 for TOS ROMs
  2373. ;    - RTS back to ROMs
  2374. ;-
  2375.     add.l    #$1c,d0        ; for file header
  2376.     move.l    d0,-(sp)
  2377.     move.l    baseaddr,-(sp)
  2378.     clr.w    -(sp)
  2379.     move.w    #$4a,-(sp)    ; Mshrink(...)
  2380.     trap    #1
  2381.     adda    #12,sp        ; (cleanup stack)
  2382.  
  2383.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  2384.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  2385.     lea    pun,a0        ; a0 = ptr to pun table
  2386.     move.w    #0,d2        ; d2 = boot dev
  2387. bd1:    cmp.b    (a0,d2.w),d1    ; d2 belongs to physical unit booted from?
  2388.     beq    bd2        ; if yes, set (d2) as boot device
  2389.     addq.w    #1,d2        ; else try next logical unit
  2390.     bra.s    bd1
  2391. bd2:    addq.w    #2,d2        ; offset for drive A and B
  2392.     move.w    d2,_bootdev    ; set default boot device to (d2)
  2393.  
  2394.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  2395.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  2396.     trap    #1
  2397.     addq.l    #4,sp        ; cleanup stack
  2398.  
  2399.     move.l    #rootpath,-(sp)    ; set root as current directory
  2400.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  2401.     trap    #1
  2402.     addq.l    #6,sp        ; cleanup stack
  2403.  
  2404.     movea.l    _sysbase,a0    ; get the system header address
  2405.     move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  2406.     cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  2407.     bcs.s    stopall        ; yup, if OS is built before 4/22/87
  2408.     move.b    puns+1,d7    ; else prevent processed units from booting
  2409.     subq.b    #1,d7        ; unit # = # of units - 1
  2410.     lsl.b    #5,d7
  2411.     bra.s    allisgd        ; finally all done
  2412.  
  2413. stopall:
  2414.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  2415. allisgd:
  2416.     pea    msg_loaded(pc)        ; print announcement
  2417.     move.w    #9,-(sp)
  2418.     trap    #1
  2419.     addq.w    #6,sp
  2420.                     ; install hdstop() in _vblqueue
  2421.     move.w    nvbls,d0        ; d0.w = # lw _vblqueue points to
  2422.     subq.w    #1,d0            ; dbra likes 1 less
  2423.     movea.l    _vblqueue,a0        ; a0 -> array of vbl handlers
  2424. nxtvbls:
  2425.     addq.w    #4,a0            ; a0 -> next slot in array
  2426.     tst.l    (a0)            ; a free (NULL) slot?
  2427.     beq.s    fvbls            ; if so, found a vblank slot
  2428.     dbra    d0,nxtvbls
  2429.                     ; if whole array is filled
  2430.     movea.l    _vblqueue,a0        ; a0 -> array of vbl handlers
  2431.     addq.w    #4,a0            ; a0 -> slot 1 of _vblqueue
  2432.     move.l    (a0),o_vblq1        ; save addr of slot 1 handler
  2433.     
  2434. fvbls:    move.l    _hz_200,hdacstm        ; init ACSI 0 last accessed time
  2435.     move.l    #hdstop,(a0)        ; install handler to _vblqueue
  2436.     rts                ; return to TOS ROMs
  2437.  
  2438. rootpath:
  2439.     dc.b    '\\',0
  2440. msg_loaded:
  2441.     dc.b    '----------------------',13,10
  2442.     dc.b    'Atari Hard Disk Driver',13,10
  2443.     dc.b    'AHDI v3.02 Apr 24 1990',13,10
  2444.     dc.b    '----------------------',13,10
  2445.     dc.b    0
  2446. .even
  2447.  
  2448. ;
  2449. ;  Terminate and stay resident;
  2450. ;  installed driver under GEMDOS.
  2451. ;
  2452. nboot2:    add.l    #$0100,d0    ; for basepage
  2453.     move.l    d0,d6
  2454.  
  2455.     move.w    nvbls,d0    ; d0.w = # lw _vblqueue points to
  2456.     subq.w    #1,d0        ; dbra likes 1 less
  2457.     movea.l    _vblqueue,a0    ; a0 -> array of vbl handlers
  2458. nxt0vbls:            ; skip entry 0
  2459.     addq.w    #4,a0        ; a0 -> next slot in array
  2460.     tst.l    (a0)        ; a free (NULL) slot?
  2461.     beq.s    f0vbls        ; if so, found a vblank slot
  2462.     dbra    d0,nxt0vbls
  2463.                 ; if whole array is filled
  2464.     movea.l    _vblqueue,a0    ; a0 -> array of vbl handlers
  2465.     addq.w    #4,a0        ; a0 -> slot 1 of _vblqueue
  2466.     move.l    (a0),o_vblq1    ; save addr of slot 1 handler
  2467.     
  2468. f0vbls:    move.l    _hz_200,hdacstm    ; init ACSI 0 last accessed time
  2469.     move.l    #hdstop,(a0)    ; install handler to _vblqueue
  2470.  
  2471.     move.l    savssp,-(sp)    ; become a mild mannered user process
  2472.     move.w    #$20,-(sp)    ; Super(savssp)
  2473.     trap    #1
  2474.     addq.l    #6,sp        ; clean up stack
  2475.  
  2476.     move.w    #0,-(sp)    ; exit code
  2477.     move.l    d6,-(sp)
  2478.     move.w    #$31,-(sp)    ; terminate and stay resident
  2479.     trap    #1        ; Ptermres() - should never come back...
  2480.     illegal
  2481.  
  2482.  
  2483.  
  2484. ;+
  2485. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  2486. ;
  2487. ; Passed:
  2488. ;     a0.l = head of buffer list            (not changed)
  2489. ;    d0.l = size of each BCB (including data block)    (not changed)
  2490. ;    d1.w = count
  2491. ;         = number of buffers to be installed to the list - 1
  2492. ;
  2493. ; Uses:
  2494. ;    d1, a1
  2495. ;-
  2496. list_init:
  2497.     move.l    a0,-(sp)    ; save head of buffer list
  2498. lin0:    movea.l    a0,a1        ; a1 = ptr to next BCB
  2499.     adda.l    d0,a1        ;    = ptr to curr BCB + size of BCB
  2500.     move.l    a1,(a0)        ; b_link -> next BCB
  2501.     move.w    #-1,4(a0)    ; b_neg1 = -1
  2502.     adda.w    #BCBLEN,a0    ; a0 = ptr to BCB data block
  2503.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  2504.     movea.l    a1,a0
  2505.     dbra    d1,lin0
  2506.     suba.l    d0,a0        ; a0 = ptr to last BCB
  2507.     clr.l    (a0)        ; lastBCB.b_link = NULL
  2508.     move.l    (sp)+,a0    ; restore head of buffer list
  2509.     rts
  2510.  
  2511.  
  2512. ;+
  2513. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  2514. ;        buffer lists
  2515. ;
  2516. ; Returns:
  2517. ;    d0.l = size of each BCB (including data block)
  2518. ;         or -1 if not enough memory is allocated
  2519. ;
  2520. ; Uses:
  2521. ;    d0, d1
  2522. ;-
  2523. chklstmem:
  2524.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  2525.     add.w    maxssz,d0    ;      = BCB header len + data block size
  2526.     move.l    d0,d1        ; d1.l = d0.l * 4 
  2527.     lsl.l    #2,d1        ;      = total size of buffer lists
  2528.     add.l    tokeep,d1    ; d1.l = size needed
  2529.     cmp.l    memalloc,d1    ; enough memory allocated?
  2530.     bls.s    chk0        ; if so return
  2531.     moveq    #-1,d0        ; else return error
  2532. chk0:    rts
  2533.  
  2534.  
  2535. ;
  2536. ;+
  2537. ; pread(sectno, cnt, buf, physunit, flag)
  2538. ; LONG sectno;
  2539. ; BYTE *buf; (word aligned)
  2540. ; WORD cnt,physunit,flag;
  2541. ;
  2542. ; Passed:    flag.w            $10(sp)    
  2543. ;        dev.w        $a(a0)    $e(sp)
  2544. ;        &buf.l        $6(a0)    $a(sp)
  2545. ;        cnt.w        $4(a0)    $8(sp)
  2546. ;        sectno.l    $0(a0)    $4(sp)
  2547. ;
  2548. ; flag = 1 -- return media change if detected
  2549. ; flag = 0 -- ignore media change
  2550. ;
  2551. ; Returns:    -1 if we could not read it
  2552. ;            (may not exist)
  2553. ;-
  2554. _pread:
  2555. pread:    move    _retries,retrycnt
  2556. pread1:    lea    4(sp),a0        ; frame pointer
  2557.     move.w    $a(a0),-(sp)        ; push physical unit number
  2558.     move.l    $6(a0),-(sp)        ; buffer address
  2559.     move.w    $4(a0),-(sp)        ; number to read
  2560.     move.l    (a0),-(sp)        ; sector number
  2561.     bsr    _hread            ; hread()
  2562.     adda    #12,sp            ; clean up stack
  2563.     tst.w    d0            ; read successful
  2564.     beq    pread8            ; if so, return
  2565.     bmi.s    pread9            ; timeout, does not exist
  2566.                     ; else, it's check condition status
  2567.     move.w    $e(sp),cpun        ; cpun = current physical unit #
  2568.     bsr    errcode            ; find error code
  2569.  
  2570.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  2571.     beq.s    preadd            ; if so, return drive not ready
  2572.  
  2573.     tst.w    $10(sp)            ; ignore media change?
  2574.     beq.s    preadc            ; if so, next try
  2575.                     ; else see if it's media change error
  2576.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  2577.     beq.s    pread7            ; if so, return media change
  2578.  
  2579. preadc:    subq    #1,retrycnt        ; else try try again
  2580.     bpl    pread1
  2581.  
  2582. pread9:    moveq    #EREADF,d0        ; read error
  2583.     rts
  2584.  
  2585. pread7:    moveq    #E_CHNG,d0        ; return media change detected
  2586.     rts
  2587.  
  2588. preadd:    moveq    #EDRVNR,d0        ; drive not ready
  2589.     rts
  2590.  
  2591. pread8:    clr.l    d0            ; flag no errors
  2592.     rts
  2593.  
  2594.  
  2595. ;
  2596. ;+
  2597. ; critic - call up the critical error handler.
  2598. ;
  2599. ; Passed:
  2600. ;    d0.w = error code
  2601. ;    d1.w = drive # excluding A: and B:
  2602. ;
  2603. ; Uses:
  2604. ;    d0, d1, a0
  2605. ;
  2606. ; Returns:
  2607. ;    d0.l = whatever returned by the critical handler
  2608. ;        (magic RETRY code or something)
  2609. ;-
  2610. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2611.     move.w    d1,-(sp)        ; drive #
  2612.     move.w    d0,-(sp)        ; error code
  2613.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2614.     jsr    (a0)            ; critic_handler(error, drive)
  2615.     addq.l    #4,sp            ; clean up stack
  2616.     rts                ; return
  2617.  
  2618.  
  2619. ;+
  2620. ; errcode - find error code for previous Check Condition Status
  2621. ;
  2622. ; Assumed:
  2623. ;    cpun = current physical unit number
  2624. ;
  2625. ; Returns:
  2626. ;    d0.b = error code    (aka additional sense code)
  2627. ;-
  2628. errcode:
  2629.     move.w    cpun,d0            ; d0 = physical unit number
  2630.     move.l    #sendata,-(sp)        ; sense data buffer
  2631.     move.w    d0,-(sp)        ; physical unit number
  2632.     btst.b    d0,scsi            ; embedded SCSI unit?
  2633.     beq.s    err0            ; if not, request non-extended sense
  2634.     bsr    _rq_xsense        ; else request extended sense
  2635.     tst.w    d0            ; successful?
  2636.     bne.s    err1            ; if not, return
  2637.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2638.     move.b    12(a0),d0        ; else d0.b = error code
  2639.     bra.s    err2            ; and return
  2640. err0:    bsr    _rq_sense        ; find out error code
  2641.     tst.w    d0            ; successful?
  2642.     bne.s    err1            ; if not, return
  2643.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2644.     move.b    (a0),d0            ; else d0.b = error code
  2645.     andi.b    #$7f,d0            ; mask valid bit
  2646.     bra.s    err2            ; and return
  2647. err1:    moveq    #-1,d0            ; error occurred
  2648. err2:    addq.l    #6,sp            ; cleanup stack
  2649.     rts
  2650.  
  2651.  
  2652. ;
  2653. ;----------------- Stop ACSI unit 0 ------------------
  2654.  
  2655. ;---------------
  2656. ;
  2657. ; Stop ACSI unit 0 if idle cnt approaches the limit.
  2658. ; This routine is executed at Timer C (_hz_200) interrupts.
  2659. ;
  2660. ;-
  2661. hdstop:
  2662.     tst.b    slock        ; is shipped variable locked?
  2663.     bne.s    hdend        ; if it is, done
  2664.     tst.b    shipped        ; else, is ACSI 0 already stopped?
  2665.     bne.s    hdend        ; if it is, done
  2666.                 ; else check if need to stop it
  2667.     move.l    idlelmt,d0    ; d0.l = idle time limit
  2668.     andi.l    #$00ffffff,d0    ; zero out high byte
  2669.     beq.s    hdend        ; if idle time limit is 0, never spin down
  2670.     add.l    hdacstm,d0    ; d0.l = time to turn off hard disk
  2671.     cmp.l    _hz_200,d0    ; pass the limit yet?
  2672.     bgt.s    hdend        ; if not, done
  2673.                 ; else stop the hard disk
  2674.     move.w    #SHIP,-(sp)    ; stop the unit
  2675.     move.w    #0,-(sp)    ; ACSI unit 0
  2676.     bsr    _stunit        ; stunit(physunit, SHIP)
  2677.     addq.w    #4,sp        ; clean up stack
  2678.     st    shipped
  2679.  
  2680. .if    onscreen
  2681.     movea.l    screen,a0    ; announce disk is shipped
  2682.     move.l    #$33333333,(a0)
  2683. .endif
  2684.  
  2685. hdend:    tst.l    o_vblq1        ; any handler address saved?
  2686.     beq.s    hdret        ; if not, just return
  2687.     move.l    o_vblq1,a0    ; else a0 -> next handler
  2688.     jmp    (a0)        ; go there
  2689. hdret:    rts            ; return to caller
  2690.  
  2691.  
  2692. ;
  2693. ;----------------- OS Pool Expansion ------------------
  2694.  
  2695. .if ospool
  2696. ;---------------
  2697. ;
  2698. ;  Wire more pool into various ROM releases.
  2699. ;
  2700. ;    Passed:    nothing
  2701. ;    Returns:    D0 = #bytes extra used
  2702. ;
  2703. ;-
  2704. pool_install:
  2705.     move.l    _sysbase,a3        ; a3 -> base of OS
  2706.  
  2707. ; make sure we're in ROM,
  2708. ; then get address of RAM location to patch:
  2709.  
  2710.     cmp.l    #$800000,a3        ; better be ROM
  2711.     blt    notrom
  2712.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2713. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2714.     beq    badrom            ; (forget it, end of list)
  2715.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2716.     cmp.l    $18(a3),d1        ; match dates?
  2717.     bne.s    pi_lp            ; (no -- try again)
  2718.  
  2719.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2720.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2721.     move.l    d0,d1            ; d1 = total memory needed
  2722.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2723.     cmp.l    memalloc,d1        ; enough is allocated?
  2724.     bgt.s    bdrom2            ; if not, don't add any
  2725.                     ; else install more OS pool
  2726.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2727.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2728.     move.l    a0,-(sp)        ; save base of first buffer
  2729.     move.w    numchunks,d1        ; d0 = count-1
  2730.     subq.w    #1,d1
  2731. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2732.     move.l    a1,(a0)            ; buffer -> next one
  2733.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2734.     move.l    a1,a0            ; a0 -> next buffer
  2735.     dbra    d1,pin_1        ; (do some more)
  2736.  
  2737.     sub.w    #chunksiz,a0        ; a0 -> last block
  2738.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2739.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2740.     rts                ; return OK
  2741.  
  2742. ;+
  2743. ;  Print warning messages
  2744. ;  about bogus versions of the
  2745. ;  operating system.  Assume that
  2746. ;  every OS past 1-May-1986 has the
  2747. ;  pool fix installed.
  2748. ;
  2749. ;-
  2750. ok_date    =    %0000110010100001    ; 1-May-1986
  2751. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2752.     bra.s    bdrom1
  2753. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2754. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2755.     bcc    bdrom2            ; then don't print anything
  2756.  
  2757.     move.l    a0,-(sp)        ; print nasty message
  2758.     move.w    #9,-(sp)
  2759.     trap    #1
  2760.     addq.l    #6,sp
  2761.  
  2762. ; print msg and wait for RETURN
  2763.     pea    keymsg(pc)
  2764.     move.w    #9,-(sp)
  2765.     trap    #1
  2766.     addq.l    #6,sp
  2767.  
  2768. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2769.     move.w    #2,-(sp)
  2770.     trap    #13
  2771.     addq.l    #4,sp
  2772.     cmp.w    #13,d0
  2773.     bne    bdrom3
  2774.  
  2775. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2776.     rts
  2777.  
  2778. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2779.     dc.b    'key to continue:',13,10
  2780.     dc.b    0
  2781.  
  2782. m_notrom:
  2783.     dc.b    '*** WARNING ***',13,10,7
  2784.     dc.b    'This hard disk driver may not work with',13,10,7
  2785.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2786.     dc.b    'your hard disk may be damaged.',13,10,7
  2787.     dc.b    13,10,7
  2788.     dc.b    0
  2789.  
  2790. m_badrom:
  2791.     dc.b    '*** WARNING ***',13,10,7
  2792.     dc.b    'You are using an unofficial ROM release',13,10,7
  2793.     dc.b    'of the operating system.  This driver',13,10,7
  2794.     dc.b    'may not work correctly with it.  Files',13,10,7
  2795.     dc.b    'on your hard disk may be damaged.',13,10,7
  2796.     dc.b    13,10,7
  2797.     dc.b    0
  2798.     even
  2799.  
  2800.  
  2801. ;+
  2802. ;  Table of ROM release dates / _root addresses
  2803. ;  update these for new ROM releases that need the patch.
  2804. ;
  2805. ;-
  2806. pool_tab:
  2807.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2808.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2809.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2810.     dc.l    0            ; end of list
  2811.  
  2812. .endif
  2813.  
  2814.  
  2815. ;
  2816. ;------------------ Driver Installation -----------------
  2817.  
  2818. ;----------------
  2819. ;
  2820. ;  Driver Installation
  2821. ;
  2822. i_sasi1:
  2823.     move.l    d0,memalloc        ; record amount of memory available
  2824.     tst.w    bootloaded        ; if boot-loaded, don't Super()
  2825.     bne    nboot3
  2826.     clr.l    -(sp)            ; it's a bird...
  2827.     move.w    #$20,-(sp)        ;    ... it's a plane ...
  2828.     trap    #1            ;      ... no, its:
  2829.     addq.l    #6,sp            ; SOOUPERUSER!
  2830.     move.l    d0,savssp        ; "Faster than a prefetched opcode..."
  2831.  
  2832. nboot3:    move    #MAXUNITS-1,d1
  2833.     moveq    #-1,d0            ; a bad pun
  2834.     lea    pun,a0
  2835. i_sasi2:
  2836.     move.b    d0,(a0)+        ; initialize all puns to be bad
  2837.     dbra    d1,i_sasi2
  2838.  
  2839.     move    #0,clun            ; cur log unit# excluding drive A & B
  2840.     move.l    #4,cdbit        ; current drive bit
  2841.     move    #0,cpun            ; current physical unit number
  2842.     move    #0,puns            ; no physical units found
  2843.     move    minbigsect,maxssz    ; initialize maximum sector size
  2844.  
  2845.     move.l    _dskbufp,pbuf        ; pbuf = buffer address of
  2846.     add.l    #512,pbuf        ;     root sector image
  2847. i_sasi3:
  2848.     clr.w    -(sp)            ; ignore media change
  2849.     move.w    cpun,-(sp)        ; physical unit number
  2850.     move.l    pbuf,-(sp)        ; buffer
  2851.     move.w    #1,-(sp)        ; 1 sector
  2852.     move.l    #0,-(sp)        ; sectno = 0; root sector
  2853.     bsr    pread            ; pread()
  2854.     adda    #14,sp
  2855.     move.w    d0,preadret        ; save pread return code
  2856.  
  2857.     movea.l    #sendata,a0        ; a0 = address of sense data buffer
  2858.     clr.l    (a0)            ; fill buffer with 0's
  2859.     clr.l    4(a0)
  2860.     clr.l    8(a0)
  2861.     clr.l    $c(a0)
  2862.     move.l    a0,-(sp)        ; buffer for data inquired
  2863.     move.w    cpun,-(sp)        ; current physical unit
  2864.     bsr    _inquiry        ; inquiry(physunit, buf)
  2865.     addq.l    #6,sp            ; clean up stack
  2866.     tst.w    d0            ; Inquiry successful?
  2867.     bne.s    chkret            ; if not, unit isn't a SCSI device
  2868.                     ; else unit is a SCSI device
  2869.     movea.l    #sendata,a0        ; a0 = address of sense data
  2870.     tst.b    (a0)            ; is unit a hard drive?
  2871.     bne.s    i_sasi4            ; if not, end of chain
  2872.     move.w    cpun,d1            ; else d1 = physical unit #
  2873.     bset.b    d1,scsi            ; mark unit as embedded scsi
  2874.     btst.b    #7,1(a0)        ; removable drive?
  2875.     beq.s    chkret            ; if not removable, was read ok?
  2876.     bset.b    d1,rmbits        ; else mark unit as removable
  2877.     bra.s    found1
  2878. chkret:    tst.w    preadret        ; was pread successful?
  2879.     bne.s    i_sasi4            ; if not, not an ACSI unit, return
  2880. found1:    addq    #1,puns            ; else found a physical unit
  2881.     bsr    ppu            ; find out how it is partitioned
  2882.     tst.w    d0            ; ppu successful?
  2883.     beq.s    nxtpun            ; go on normally
  2884.                     ; else find out what's wrong
  2885.     cmpi.w    #E_CHNG,d0        ; media changed?
  2886.     beq    i_sasi3            ; if so, retry this unit
  2887.                     ; else try next physical unit
  2888. nxtpun:    addq.w    #1,cpun            ; next physical unit
  2889.     cmpi.w    #MAXACSI,cpun        ; last one yet?
  2890.     bne    i_sasi3            ; if not, continue
  2891.  
  2892. i_sasi4:                ; save current vectors for
  2893.     move.l    hdv_bpb,o_bpb        ; Getbpb()
  2894.     move.l    hdv_rw,o_rw        ; Rwabs()
  2895.     move.l    hdv_mediach,o_mediach    ; Mediach()
  2896.  
  2897. .if    onscreen
  2898.     move.l    _v_bas_ad,screen    ; screen = base of screen memory
  2899. .endif
  2900.     
  2901.     move.l    #hbpb,hdv_bpb        ; install our new ones
  2902.     move.l    #hrw,hdv_rw
  2903.     move.l    #hmediach,hdv_mediach
  2904.     move.l    #_puns,pun_ptr
  2905.  
  2906.     move.l    #_cookie,cookptr    ; initialize cookie pointer
  2907.     bra    isasi5            ; must get back into resident part
  2908.  
  2909.  
  2910. ;
  2911. ;-----------------
  2912. ;
  2913. ; Partition physical unit
  2914. ;
  2915. ;
  2916. ppu:    move.w    #0,npart        ; no partition found for cpun yet
  2917.     move.w    cpun,d1            ; is cpun removable?
  2918.     btst.b  d1,rmbits        ;
  2919.     beq.s    ppu0            ; if not, go on normally
  2920.                     ; else, it's a syquest unit
  2921.     tst.w    preadret        ; is there a cartridge in there?
  2922.     bne.s    squnit            ; if not, go reserve #drv letters
  2923.                     ; else find the partitions
  2924. ppu0:    moveq    #MAXNPART,d1        ; d1 = # partition entries to check
  2925.     movea.l    pbuf,a0            ; a0 = ptr to root sector image
  2926.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  2927.     bne.s    ppu1            ; if not, assume it's in ST format
  2928.     bsr    dosppu            ; else, handle it the DOS way
  2929.     bra.s    ppu2
  2930. ppu1:    bsr    gemppu
  2931. ppu2:    tst.w    d0            ; successful?
  2932.     bne.s    ppud            ; if not, return
  2933.  
  2934.     lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2935.     move.w    cpun,d1            ; d1 = unit #
  2936.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2937.     sub.w    npart,d1        ; enough drives being set up?
  2938.     bls.s    ppud            ; if so, done
  2939.                     ; else see if it's removable
  2940.     move.w    cpun,d0            ; d0 = unit #
  2941.     btst.b    d0,rmbits        ; is cpun removable?
  2942.     beq.s    ppud            ; if not, done
  2943.     bra.s    sq0            ; else, set up the rest
  2944.  
  2945. squnit:    lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2946.     move.w    cpun,d1            ; d1 = unit #
  2947.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2948. sq0:    subq.w    #1,d1
  2949. ppu3:    move.w    d1,-(sp)        ; save count
  2950.     bsr    nxtd0
  2951.     move.w    (sp)+,d1        ; restore count
  2952.     tst.w    d0            ; a valid unit?
  2953.     bmi.s    ppud            ; if not, return
  2954.     dbra    d1,ppu3
  2955. ppud:    rts
  2956.  
  2957.  
  2958. ;
  2959. ;+
  2960. ; dosppu - find the DOS partitions of the drive and set up
  2961. ;       appropiate data structures.
  2962. ; Passed:
  2963. ;    a0 = buffer address for root sector
  2964. ;    d1 = number of entries in partition map
  2965. ;
  2966. ; Returns:
  2967. ;    d0 = 0            if no error
  2968. ;       = negative #        if error found
  2969. ;-
  2970. dosppu:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  2971. dppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2972.     sf    ext            ; not dealing with ext partition
  2973.     bsr    fdpart            ; find partitions
  2974.     tst.b    d0            ; found any?
  2975.     beq.s    dppua            ; not a valid partition
  2976.     cmpi.b    #5,d0            ; extended partition?
  2977.     bne.s    dppu1            ; if not, it's a regular partition
  2978.     st    ext            ; else, it's an extended partition
  2979.     move.l    #0,extvol        ; offset from start of partition = 0
  2980.     move.l    d1,extrt        ; starting sector # of ext partition
  2981. dppux:    bsr    fdnxt            ; find next logical drive
  2982.     tst.b    d0            ; found any?
  2983.     beq.s    dppua            ; no logical drive found
  2984.     bmi.s    dppu2            ; error returned
  2985.     cmpi.b    #5,d0            ; extended volume?
  2986.     beq.s    dppux            ; if so, go find next logical drive
  2987. dppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2988.     bsr    nxtdrv            ; general set up for clun
  2989.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2990.     tst.w    d0            ; set up successful?
  2991.     beq.s    dppu3            ; if successful, continue
  2992. dppu2:    addq.l    #8,sp            ; else clean up stack
  2993.     bra.s    dppur            ; and return
  2994. dppu3:    tst.b    ext            ; clun is in ext partition?
  2995.     bne.s    dppux            ; if so, go find next ext vol
  2996. dppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2997.     adda    #16,a0            ; index to next entry in pmap
  2998.     dbra    d1,dppu0
  2999.     moveq    #0,d0            ; get here with no error!
  3000. dppur:    rts
  3001.  
  3002.  
  3003. ;
  3004. ;+
  3005. ; gemppu - find the GEMDOS partitions of the drive and set up
  3006. ;       appropiate data structures.
  3007. ; Passed:
  3008. ;    a0 = buffer address for root sector
  3009. ;    d1 = number of entries in partition map
  3010. ;
  3011. ; Returns:
  3012. ;    d0 = 0            if no error
  3013. ;       = negative #        if error found
  3014. ;-
  3015. gemppu:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  3016.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  3017.     beq.s    gppu4            ; if =0, no drive will exist
  3018. gppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  3019.     sf    ext            ; not dealing with ext partition
  3020.     bsr    fgpart            ; find partitions
  3021.     tst.b    d0            ; found any?
  3022.     beq.s    gppua            ; not a valid partition
  3023.     cmpi.b    #'X',d0            ; extended partition?
  3024.     bne.s    gppu1            ; if not, it's a regular partition
  3025.     st    ext            ; else, it's an extended partition
  3026.     move.l    #0,extvol        ; offset from start of partition = 0
  3027.     move.l    d1,extrt        ; starting sector # of ext partition
  3028. gppux:    bsr    fgnxt            ; find next logical drive
  3029.     tst.b    d0            ; found any?
  3030.     beq.s    gppua            ; no logical drive found
  3031.     bmi.s    gppu2            ; error returned
  3032.     cmpi.b    #'X',d0            ; extended volume?
  3033.     beq.s    gppux            ; if so, go find next logical drive
  3034. gppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  3035.     bsr    nxtdrv            ; general set up for clun
  3036.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  3037.     tst.w    d0            ; set up successful?
  3038.     beq.s    gppu3            ; if so, continue
  3039. gppu2:    addq.l    #8,sp            ; else clean up stack
  3040.     bra.s    gppur            ; and return
  3041. gppu3:    tst.b    ext            ; clun is in ext partition?
  3042.     bne.s    gppux            ; if so, go find next ext vol
  3043. gppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  3044.     adda    #12,a0            ; index to next entry in pmap
  3045.     dbra    d1,gppu0
  3046. gppu4:    moveq    #0,d0            ; get here with no error!
  3047. gppur:    rts
  3048.  
  3049.  
  3050. ;
  3051. ;+
  3052. ; nxtdrv    (of clun, cdbit)
  3053. ;
  3054. ; Passed:
  3055. ;    d1.l = starting sector # of clun
  3056. ; Returns:
  3057. ;    d0 = 0            if successful
  3058. ;       = negative #        if error occurred
  3059. ;-
  3060. nxtdrv:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  3061.     bge    nxtd9            ; yes, so signal error
  3062.  
  3063.     move.w    #1,-(sp)        ; return media change if detected
  3064.     move.w    cpun,-(sp)        ; physical unit number
  3065.     move.l    #sbuf,-(sp)        ; buffer address
  3066.     move.w    #1,-(sp)        ; 1 sector
  3067.     move.l    d1,-(sp)        ; logical sector 0 of clun
  3068.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  3069.     adda    #14,sp            ; clean up stack
  3070.     tst.w    d0            ; pread successful?
  3071.     bne    nxtr            ; if not, return with error code
  3072.  
  3073.     move.l    #sbuf,a0        ; a0 = addr of boot sector image
  3074.     moveq    #$b,d0            ; d0 = offset for bytes per sector
  3075.     bsr    getlhw
  3076.     tst.w    d0            ; bytes per sector = 0?
  3077.     beq.s    nxtd1            ; if so, assume ratio to be 1
  3078.  
  3079.     cmp.w    maxssz,d0        ; max sect size >= curr sect size?
  3080.     bls.s    nxtd00            ; if so, continue
  3081.     move.w    d0,maxssz        ; else max sect size = curr sect size
  3082. nxtd00:    divu    #512,d0            ; d0 = sector size ratio
  3083.     move.w    d0,sizr            ; sizr = sector size ratio
  3084.     bra.s    nxtd2            ; go on
  3085.  
  3086. nxtd0:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  3087.     bge    nxtd9            ; yes, so signal error
  3088.  
  3089. nxtd1:    move.w    #1,sizr            ; sector size ratio assumes to be 1
  3090.  
  3091. nxtd2:    move.l    cdbit,d1        ; get the bit to turn on
  3092.     move.l    _drvbits,d0        ; tell TOS we have the drive
  3093.     or.l    d1,d0
  3094.     move.l    d0,_drvbits
  3095.  
  3096.     asl.l    #1,d1            ; put in the next bit to turn on
  3097.     move.l    d1,cdbit
  3098.  
  3099.     move    clun,d0            ; d0 = dev number
  3100.     lea    pun,a0            ; a0 = ptr to pun table
  3101.     move.b    cpun+1,(a0,d0.w)    ; clun belongs to cpun
  3102.  
  3103.     lea    sratio,a0        ; a0 = ptr to sector size ratio table
  3104.     move.b    sizr+1,(a0,d0.w)    ; save sector ratio of clun
  3105.  
  3106.     lea    xst,a0            ; a0 = ptr to drive existence table
  3107.     move.b    #1,(a0,d0.w)        ; clun may exist
  3108.  
  3109.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  3110.     move.b    #2,(a0,d0.w)        ; clun is definitely changed
  3111.  
  3112.     addq    #1,clun            ; clun = next possible lun
  3113.     addq    #1,npart        ; one more partition found
  3114.     moveq    #0,d0            ; gets here with no error
  3115.     bra.s    nxtr
  3116.  
  3117. nxtd9:    moveq    #-1,d0            ; error!
  3118. nxtr:    rts
  3119.  
  3120.  
  3121. ;
  3122. .if    format
  3123. ;----------------
  3124. ;
  3125. ;  Parameter Block
  3126. ;
  3127. acfmt:    dc.b    4    ; format command + devno (upper 3 bits)
  3128.     dc.b    0    ; (unused)
  3129.     dc.b    0    ; (unused) data pattern
  3130. ac_in:    dc.b    0,0    ; interleave factor MSB, LSB
  3131.     dc.b    0    ; reserved
  3132. .even
  3133.  
  3134. ;---------------
  3135. ;
  3136. ;  _doformat - format hard disk
  3137. ;
  3138. ;    Synopsis:    LONG _doformat(dev, interlv)
  3139. ;        WORD dev;            4(sp).W
  3140. ;        WORD interlv;            6(sp).W
  3141. ;
  3142. _doformat:
  3143.     move.w    4(sp),d0        ; set dev#
  3144.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  3145.     or.b    #4,d0            ; OR-in with FORMAT command
  3146.     move.b    d0,acfmt        ; stuff into command frame
  3147.     move.b    6(sp),ac_in        ; set interleave
  3148.     move.b    7(sp),ac_in+1
  3149.  
  3150.     lea    acfmt(pc),a0        ; pick up pointer to the command block
  3151.     clr.w    d0
  3152.     st    flock            ; lock FIFO
  3153.     move.w    #$88,wdl
  3154.     move.b    (a0)+,d0        ; get the command byte
  3155.     swap    d0
  3156.     move.w    #$8a,d0
  3157.     move.l    d0,wdc            ; byte wdc 8a wdl
  3158.  
  3159.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  3160. fmt1:    bsr    _qdone
  3161.     bmi    _hto
  3162.     move.b    (a0)+,d0        ; next byte of command
  3163.     swap    d0
  3164.     move.w    #$8a,d0
  3165.     move.l    d0,wdcwdl
  3166.     dbra    d1,fmt1
  3167.     bsr    _endcmd            ; wait for command completion
  3168.     bra    _hdone            ; cleanup after IRQ
  3169.  
  3170.  
  3171. ;
  3172. ;----------------
  3173. ;
  3174. ;  _mode_set - set hard disk format parameters
  3175. ;
  3176. ;    Synopsis:    LONG _mode_set(dev, len, parms)
  3177. ;        WORD dev;            4(sp).W
  3178. ;        WORD len;            6(sp).W
  3179. ;        char *parms;            8(sp).L
  3180. ;
  3181. _mode_set:
  3182.     st    flock            ; lock FIFO
  3183.     move.l    8(sp),-(sp)        ; -> parameter block address
  3184.     bsr    _setdma            ; set DMA there
  3185.     addq.l    #4,sp
  3186.  
  3187. ; write command and dev#
  3188.     move.w    #$88,wdl
  3189.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  3190.     lsl.b    #5,d0
  3191.     swap    d0            ; in upper word
  3192.     or.l    #$0015008a,d0        ; write dev# + ModeSelect + FIFO bits
  3193.     move.l    d0,wdcwdl        ; mdsel+dev wdc 8a wdl (byte 0)
  3194.     bsr    _qdone
  3195.     bmi    wdx
  3196.  
  3197.     move.l    #$0000008a,wdcwdl    ; byte 1
  3198.     bsr    _qdone
  3199.     bmi    wdx
  3200.  
  3201.     move.l    #$0000008a,wdcwdl    ; byte 2
  3202.     bsr    _qdone
  3203.     bmi    wdx
  3204.  
  3205.     move.l    #$0000008a,wdcwdl    ; byte 3
  3206.     bsr    _qdone
  3207.     bmi    wdx
  3208.  
  3209.     move.w    6(sp),d0        ; # bytes of parameter
  3210.     swap    d0            ; in upper word
  3211.     or.l    #$0000008a,d0
  3212.     move.l    d0,wdcwdl        ; byte 4
  3213.     bsr    _qdone
  3214.     bmi    wdx
  3215.  
  3216.     move.w    #$90,wdl        ; reset the DMA chip
  3217.     move.w    #$190,wdl
  3218.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  3219.     move.w    #$18a,wdl
  3220.     move.l    #$00000100,wdcwdl    ; byte 5 (control byte)
  3221.     move.w    #$18a,d0        ; wdl value
  3222.     bsr    _endcmd            ; wait for command completion
  3223. wdx:    bra    _hdone
  3224.  
  3225. .endif  ; format
  3226.  
  3227.   
  3228. .if    mdsense
  3229. ;----------------
  3230. ;
  3231. ;  _md_sense - get hard disk format parameters
  3232. ;
  3233. ;    Synopsis:    LONG _md_sense(dev, parms)
  3234. ;        WORD dev;            4(sp).W
  3235. ;        char *parms;            6(sp).L
  3236. ;
  3237. _md_sense:
  3238.     st    flock            ; lock FIFO
  3239.     move.l    6(sp),-(sp)        ; -> parameter block address
  3240.     bsr    _setdma            ; set DMA there
  3241.     addq.l    #4,sp
  3242.  
  3243. ; write command and dev#
  3244.     move.w    #$88,wdl
  3245.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  3246.     lsl.b    #5,d0
  3247.     swap    d0            ; in upper word
  3248.     or.l    #$001a008a,d0        ; write dev# + ModeSense + FIFO bits
  3249.     move.l    d0,wdcwdl        ; mdsense+dev wdc 8a wdl (byte 0)
  3250.     bsr    _qdone
  3251.     bmi    wdx1
  3252.  
  3253.     move.l    #$0000008a,wdcwdl    ; byte 1
  3254.     bsr    _qdone
  3255.     bmi    wdx1
  3256.  
  3257.     move.l    #$0000008a,wdcwdl    ; byte 2
  3258.     bsr    _qdone
  3259.     bmi    wdx1
  3260.  
  3261.     move.l    #$0000008a,wdcwdl    ; byte 3
  3262.     bsr    _qdone
  3263.     bmi    wdx1
  3264.  
  3265.     move.l    #$0016008a,wdcwdl    ; 22 bytes of parameters (byte 4)
  3266.     bsr    _qdone
  3267.     bmi    wdx1
  3268.  
  3269.     move.w    #$190,wdl        ; reset the DMA chip
  3270.     move.w    #$90,wdl
  3271.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  3272.     move.w    #$8a,wdl
  3273.     move.l    #0,wdcwdl        ; byte 5 (control byte)
  3274.     move.w    #$8a,d0            ; wdl value
  3275.     bsr    _endcmd            ; wait for command completion
  3276. wdx1:    bra    _hdone
  3277.  
  3278. .endif  ; mdsense
  3279.  
  3280.     bss
  3281. clun:    ds.w    1            ; current logical unit
  3282. cdbit:    ds.l    1            ; current drive bit
  3283. sbuf:    ds.b    512            ; temporary buffer for i/o
  3284.     end
  3285.